|
OOFEM
2.1
|
00001 /* 00002 * 00003 * ##### ##### ###### ###### ### ### 00004 * ## ## ## ## ## ## ## ### ## 00005 * ## ## ## ## #### #### ## # ## 00006 * ## ## ## ## ## ## ## ## 00007 * ## ## ## ## ## ## ## ## 00008 * ##### ##### ## ###### ## ## 00009 * 00010 * 00011 * OOFEM : Object Oriented Finite Element Code 00012 * 00013 * Copyright (C) 1993 - 2013 Borek Patzak 00014 * 00015 * 00016 * 00017 * Czech Technical University, Faculty of Civil Engineering, 00018 * Department of Structural Mechanics, 166 29 Prague, Czech Republic 00019 * 00020 * This program is free software; you can redistribute it and/or modify 00021 * it under the terms of the GNU General Public License as published by 00022 * the Free Software Foundation; either version 2 of the License, or 00023 * (at your option) any later version. 00024 * 00025 * This program is distributed in the hope that it will be useful, 00026 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00027 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00028 * GNU General Public License for more details. 00029 * 00030 * You should have received a copy of the GNU General Public License 00031 * along with this program; if not, write to the Free Software 00032 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00033 */ 00034 #ifdef __PARALLEL_MODE 00035 00036 #include "nonlocalmatwtp.h" 00037 #include "nonlocalmaterialext.h" 00038 #include "element.h" 00039 #include "gausspnt.h" 00040 #include "material.h" 00041 #include "communicator.h" 00042 #include "datastream.h" 00043 #include "domaintransactionmanager.h" 00044 #include "usrdefsub.h" 00045 00046 #include <set> 00047 00048 namespace oofem { 00049 #define NonlocalMaterialWTP_DEBUG_PRINT 0 00050 00051 /* 00052 * Returns array storing nonlocal dependency 00053 * (in terms of global element numbers) for given element 00054 */ 00055 void 00056 NonlocalMaterialWTP :: giveElementNonlocalDepArry(IntArray &answer, Domain *d, int num) 00057 { 00058 int _i; 00059 std :: set< int >relems; 00060 std :: set< int > :: const_iterator relemsIter; 00061 Element *ielem = d->giveElement(num); 00062 00063 if ( ielem->giveMaterial()->giveInterface(NonlocalMaterialExtensionInterfaceType) ) { 00064 relems.clear(); 00065 // loop over element IRules and their IPs to retrieve remote (nonlocal) elements 00066 // store their global numbers in the relems set (to avoid redundancy) 00067 // and then keep them in nonlocTables array. 00068 ielem->ipEvaluator(this, & NonlocalMaterialWTP :: giveNonlocalDepArryElementPlugin, relems); 00069 00070 // convert relems set into an int array 00071 // and store it 00072 answer.resize( relems.size() ); 00073 for ( relemsIter = relems.begin(), _i = 1; relemsIter != relems.end(); ++relemsIter, _i++ ) { 00074 answer.at(_i) = * relemsIter; 00075 } 00076 } else { 00077 answer.resize(0); 00078 } 00079 } 00080 00081 00082 void 00083 NonlocalMaterialWTP :: giveNonlocalDepArryElementPlugin(GaussPoint *gp, std :: set< int > &s) 00084 { 00085 int remoteElemNum; 00086 00087 NonlocalMaterialStatusExtensionInterface *interface = 00088 static_cast< NonlocalMaterialStatusExtensionInterface * >( gp->giveElement()->giveMaterial()-> 00089 giveStatus(gp)->giveInterface(NonlocalMaterialStatusExtensionInterfaceType) ); 00090 if ( interface ) { 00091 std::list< localIntegrationRecord > *lir = interface->giveIntegrationDomainList(); 00092 std::list< localIntegrationRecord > :: iterator listIter; 00093 00094 for ( listIter = lir->begin(); listIter != lir->end(); ++listIter ) { 00095 remoteElemNum = ( ( * listIter ).nearGp )->giveElement()->giveGlobalNumber(); 00096 s.insert(remoteElemNum); 00097 } 00098 } 00099 } 00100 00101 00102 /* 00103 * prepares the communication maps for remote elements 00104 * should be called immediately after load balancing, 00105 * before any work transfer. 00106 * 00107 */ 00108 void 00109 NonlocalMaterialWTP :: init(Domain *domain) 00110 { 00111 int ie, gie, nelem = domain->giveNumberOfElements(); 00112 EngngModel *emodel = domain->giveEngngModel(); 00113 Element *elem; 00114 int nproc = emodel->giveNumberOfProcesses(); 00115 int myrank = emodel->giveRank(); 00116 CommunicatorBuff cb(nproc, CBT_dynamic); 00117 Communicator com(emodel, &cb, myrank, nproc, CommMode_Dynamic); 00118 this->nonlocElementDependencyMap.clear(); 00119 00120 // build nonlocal element dependency array for each element 00121 for ( ie = 1; ie <= nelem; ie++ ) { 00122 elem = domain->giveElement(ie); 00123 if ( ( elem->giveParallelMode() == Element_local ) ) { 00124 gie = elem->giveGlobalNumber(); 00125 this->giveElementNonlocalDepArry(nonlocElementDependencyMap [ gie ], domain, ie); 00126 } 00127 } 00128 00129 /* send and receive nonlocElementDependencyArry of migrating elements to remote partition */ 00130 com.packAllData(this, domain, & NonlocalMaterialWTP :: packMigratingElementDependencies); 00131 com.initExchange(MIGRATE_NONLOCALDEP_TAG); 00132 com.unpackAllData(this, domain, & NonlocalMaterialWTP :: unpackMigratingElementDependencies); 00133 com.finishExchange(); 00134 } 00135 00136 00137 00138 /* 00139 * should be called after basic local migration is finalized, 00140 * when all local elements are already available 00141 */ 00142 void 00143 NonlocalMaterialWTP :: migrate() 00144 { 00145 Domain *domain = this->lb->giveDomain(); 00146 EngngModel *emodel = domain->giveEngngModel(); 00147 int nproc = emodel->giveNumberOfProcesses(); 00148 int myrank = emodel->giveRank(); 00149 CommunicatorBuff cb(nproc, CBT_dynamic); 00150 Communicator com(emodel, &cb, myrank, nproc, CommMode_Dynamic); 00151 StaticCommunicationBuffer commBuff(MPI_COMM_WORLD); 00152 00153 /* 00154 * build domain nonlocal element dependency list. Then exclude local elements - what remains are unsatisfied 00155 * remote dependencies that have to be broadcasted and received from partitions owning relevant elements 00156 */ 00157 int _locsize, i, _i, ie, _size, _globnum, result, nelems = domain->giveNumberOfElements(); 00158 int _globsize, _val; 00159 Element *elem; 00160 std :: set< int >domainElementDepSet; 00161 std :: set< int > :: const_iterator sit; 00162 // loop over each element dep list to assemble domain list 00163 std :: vector< IntArray > :: const_iterator it; 00164 for ( ie = 1; ie <= nelems; ie++ ) { 00165 elem = domain->giveElement(ie); 00166 if ( ( elem->giveParallelMode() == Element_local ) ) { 00167 _globnum = elem->giveGlobalNumber(); 00168 IntArray &iedep = nonlocElementDependencyMap [ _globnum ]; 00169 _size = iedep.giveSize(); 00170 for ( _i = 1; _i <= _size; _i++ ) { 00171 domainElementDepSet.insert( iedep.at(_i) ); 00172 } 00173 00174 #if NonlocalMaterialWTP_DEBUG_PRINT 00175 fprintf(stderr, "[%d] element %d dependency:", myrank, _globnum); 00176 for ( _i = 1; _i <= _size; _i++ ) { 00177 fprintf( stderr, "%d ", iedep.at(_i) ); 00178 } 00179 00180 fprintf(stderr, "\n"); 00181 #endif 00182 } 00183 } 00184 00185 #if NonlocalMaterialWTP_DEBUG_PRINT 00186 fprintf(stderr, "[%d] nonlocal domain dependency:", myrank); 00187 for ( sit = domainElementDepSet.begin(); 00188 sit != domainElementDepSet.end(); ++sit ) { 00189 fprintf(stderr, "%d ", * sit); 00190 } 00191 00192 fprintf(stderr, "\n"); 00193 #endif 00194 00195 // now exclude local elements (local dependency is always satisfied) 00196 for ( _i = 1; _i <= nelems; _i++ ) { 00197 elem = domain->giveElement(_i); 00198 if ( elem->giveParallelMode() == Element_local ) { 00199 domainElementDepSet.erase( elem->giveGlobalNumber() ); 00200 } 00201 } 00202 00203 #if NonlocalMaterialWTP_DEBUG_PRINT 00204 fprintf(stderr, "[%d] remote elem wish list:", myrank); 00205 for ( sit = domainElementDepSet.begin(); 00206 sit != domainElementDepSet.end(); ++sit ) { 00207 fprintf(stderr, "%d ", * sit); 00208 } 00209 00210 fprintf(stderr, "\n"); 00211 #endif 00212 00213 // broadcast remaining elements (unsatisfied domain nonlocal dependency) to remaining partitions 00214 _locsize = domainElementDepSet.size() + 1; 00215 result = MPI_Allreduce(& _locsize, & _globsize, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); 00216 if ( result != MPI_SUCCESS ) { 00217 OOFEM_ERROR("NonlocalMaterialWTP::migrate: MPI_Allreduce to determine broadcast buffer size failed"); 00218 } 00219 00220 commBuff.resize( commBuff.givePackSize(MPI_INT, _globsize) ); 00221 // remote domain wish list 00222 std :: set< int >remoteWishSet; 00223 00224 toSendList.resize(nproc); 00225 for ( i = 0; i < nproc; i++ ) { // loop over partitions 00226 commBuff.init(); 00227 toSendList [ i ].clear(); 00228 if ( i == myrank ) { 00229 // current domain has to send its receive wish list to all domains 00230 commBuff.packInt(_locsize); 00231 for ( sit = domainElementDepSet.begin(); sit != domainElementDepSet.end(); ++sit ) { 00232 commBuff.packInt(* sit); 00233 } 00234 00235 result = commBuff.bcast(i); 00236 } else { 00237 // unpack remote domain wish list 00238 remoteWishSet.clear(); 00239 result = commBuff.bcast(i); 00240 // unpack size 00241 commBuff.unpackInt(_size); 00242 for ( _i = 1; _i < _size; _i++ ) { 00243 commBuff.unpackInt(_val); 00244 remoteWishSet.insert(_val); 00245 } 00246 00247 // determine which local elements are to be sent to remotepartition 00248 for ( _i = 1; _i <= nelems; _i++ ) { 00249 elem = domain->giveElement(_i); 00250 if ( elem->giveParallelMode() == Element_local ) { 00251 if ( remoteWishSet.find( elem->giveGlobalNumber() ) != remoteWishSet.end() ) { 00252 // store local element number 00253 toSendList [ i ].push_back(_i); 00254 } 00255 } 00256 } 00257 } 00258 } // end loop over partitions broadcast 00259 00260 #if NonlocalMaterialWTP_DEBUG_PRINT 00261 std :: list< int > :: const_iterator lit; 00262 for ( i = 0; i < nproc; i++ ) { // loop over partitions 00263 // print some info 00264 fprintf(stderr, "[%d] elements scheduled for mirroring at [%d]:", 00265 myrank, i); 00266 for ( lit = toSendList [ i ].begin(); lit != toSendList [ i ].end(); ++lit ) { 00267 fprintf( stderr, "%d[%d] ", * lit, domain->giveElement(* lit)->giveGlobalNumber() ); 00268 } 00269 00270 fprintf(stderr, "\n"); 00271 } 00272 00273 #endif 00274 00275 00276 00277 00278 00279 com.packAllData(this, domain, & NonlocalMaterialWTP :: packRemoteElements); 00280 com.initExchange(MIGRATE_REMOTE_ELEMENTS_TAG); 00281 com.unpackAllData(this, domain, & NonlocalMaterialWTP :: unpackRemoteElements); 00282 com.finishExchange(); 00283 00284 domain->commitTransactions( domain->giveTransactionManager() ); 00285 00286 #ifdef __VERBOSE_PARALLEL 00287 VERBOSEPARALLEL_PRINT("NonlocalMaterialWTP::migrate", "Finished migrating remote elements", myrank); 00288 #endif 00289 } 00290 00291 00292 void 00293 NonlocalMaterialWTP :: update() 00294 { 00295 /* Now the question is how to use nonlocElementDependencyMap, which is available for 00296 * each element, to fastly reinitialize nonlocal integration tables. 00297 * 00298 * if not needed, should be deleted at the end of migrate method, to free memory 00299 */ 00300 this->fastRebuildNonlocalTables(); 00301 // delete element dep arrays 00302 nonlocElementDependencyMap.clear(); 00303 } 00304 00305 00306 int NonlocalMaterialWTP :: packMigratingElementDependencies(Domain *d, ProcessCommunicator &pc) 00307 { 00308 int myrank = d->giveEngngModel()->giveRank(); 00309 int iproc = pc.giveRank(); 00310 00311 if ( iproc == myrank ) { 00312 return 1; // skip local partition 00313 } 00314 00315 // query process communicator to use 00316 ProcessCommunicatorBuff *pcbuff = pc.giveProcessCommunicatorBuff(); 00317 ProcessCommDataStream pcDataStream(pcbuff); 00318 00319 int ielem, nelem = d->giveNumberOfElements(); 00320 int _globnum; 00321 Element *elem; 00322 00323 for ( ielem = 1; ielem <= nelem; ielem++ ) { // begin loop over elements 00324 elem = d->giveElement(ielem); 00325 if ( ( elem->giveParallelMode() == Element_local ) && 00326 ( lb->giveElementPartition(ielem) == iproc ) ) { 00327 // pack local element (node numbers shuld be global ones!!!) 00328 // pack type 00329 _globnum = elem->giveGlobalNumber(); 00330 pcbuff->packInt(_globnum); 00331 pcbuff->packIntArray(nonlocElementDependencyMap [ _globnum ]); 00332 } 00333 } // end loop over elements 00334 00335 // pack end-of-element-record 00336 pcbuff->packInt(NonlocalMaterialWTP_END_DATA); 00337 00338 return 1; 00339 } 00340 00341 int NonlocalMaterialWTP :: unpackMigratingElementDependencies(Domain *d, ProcessCommunicator &pc) 00342 { 00343 int myrank = d->giveEngngModel()->giveRank(); 00344 int iproc = pc.giveRank(); 00345 int _globnum; 00346 00347 if ( iproc == myrank ) { 00348 return 1; // skip local partition 00349 } 00350 00351 // query process communicator to use 00352 ProcessCommunicatorBuff *pcbuff = pc.giveProcessCommunicatorBuff(); 00353 ProcessCommDataStream pcDataStream(pcbuff); 00354 00355 // unpack element data 00356 do { 00357 pcbuff->unpackInt(_globnum); 00358 if ( _globnum == NonlocalMaterialWTP_END_DATA ) { 00359 break; 00360 } 00361 00362 pcbuff->unpackIntArray(nonlocElementDependencyMap [ _globnum ]); 00363 } while ( 1 ); 00364 00365 return 1; 00366 } 00367 00368 int NonlocalMaterialWTP :: packRemoteElements(Domain *d, ProcessCommunicator &pc) 00369 { 00370 int myrank = d->giveEngngModel()->giveRank(); 00371 int iproc = pc.giveRank(); 00372 int i, ie, nnodes, inode; 00373 DofManager *node, *dofman; 00374 Element *elem; 00375 classType dtype; 00376 00377 00378 if ( iproc == myrank ) { 00379 return 1; // skip local partition 00380 } 00381 00382 // query process communicator to use 00383 ProcessCommunicatorBuff *pcbuff = pc.giveProcessCommunicatorBuff(); 00384 ProcessCommDataStream pcDataStream(pcbuff); 00385 std :: list< int > :: const_iterator it; 00386 00387 // here we have to pack also nodes that are shared by packed elements !!! 00388 // assemble set of nodes needed by those elements 00389 // these have to be send (except those that are shared) 00390 std :: set< int >nodesToSend; 00391 for ( it = toSendList [ iproc ].begin(); it != toSendList [ iproc ].end(); ++it ) { 00392 ie = * it; //ie = d->elementGlobal2Local(*it); 00393 elem = d->giveElement(ie); 00394 nnodes = elem->giveNumberOfDofManagers(); 00395 for ( i = 1; i <= nnodes; i++ ) { 00396 node = elem->giveDofManager(i); 00397 if ( ( node->giveParallelMode() == DofManager_local ) || 00398 ( node->isShared() && !node->givePartitionList()->contains(iproc) ) ) { 00399 nodesToSend.insert( elem->giveDofManager(i)->giveGlobalNumber() ); 00400 } 00401 } 00402 } 00403 00404 // pack nodes that become null nodes on remote partition 00405 std :: set< int > :: const_iterator nit; 00406 for ( nit = nodesToSend.begin(); nit != nodesToSend.end(); ++nit ) { 00407 inode = d->dofmanGlobal2Local(* nit); 00408 dofman = d->giveDofManager(inode); 00409 dtype = dofman->giveClassID(); 00410 pcbuff->packInt(dtype); 00411 dofman->saveContext(& pcDataStream, CM_Definition | CM_State | CM_UnknownDictState); 00412 } 00413 00414 pcbuff->packInt(NonlocalMaterialWTP_END_DATA); 00415 00416 for ( it = toSendList [ iproc ].begin(); it != toSendList [ iproc ].end(); ++it ) { 00417 ie = * it; //ie = d->elementGlobal2Local(*it); 00418 elem = d->giveElement(ie); 00419 // pack local element (node numbers shuld be global ones!!!) 00420 // pack type 00421 pcbuff->packInt( elem->giveClassID() ); 00422 elem->saveContext(& pcDataStream, CM_Definition | CM_DefinitionGlobal | CM_State); 00423 } 00424 00425 pcbuff->packInt(NonlocalMaterialWTP_END_DATA); 00426 00427 00428 return 1; 00429 } 00430 00431 int NonlocalMaterialWTP :: unpackRemoteElements(Domain *d, ProcessCommunicator &pc) 00432 { 00433 int myrank = d->giveEngngModel()->giveRank(); 00434 int iproc = pc.giveRank(); 00435 int _type; 00436 classType _etype; 00437 DofManager *dofman; 00438 IntArray _partitions; 00439 00440 if ( iproc == myrank ) { 00441 return 1; // skip local partition 00442 } 00443 00444 // query process communicator to use 00445 ProcessCommunicatorBuff *pcbuff = pc.giveProcessCommunicatorBuff(); 00446 ProcessCommDataStream pcDataStream(pcbuff); 00447 00448 // unpack null dofmans 00449 pcbuff->unpackInt(_type); 00450 // unpack dofman data 00451 while ( _type != NonlocalMaterialWTP_END_DATA ) { 00452 _etype = ( classType ) _type; 00453 dofman = CreateUsrDefDofManagerOfType(_etype, 0, d); 00454 dofman->restoreContext(& pcDataStream, CM_Definition | CM_State | CM_UnknownDictState); 00455 dofman->setParallelMode(DofManager_null); 00456 if ( d->dofmanGlobal2Local( dofman->giveGlobalNumber() ) ) { 00457 // record already exist 00458 delete dofman; 00459 } else { 00460 d->giveTransactionManager()->addTransaction(DomainTransactionManager :: DTT_ADD, 00461 DomainTransactionManager :: DCT_DofManager, 00462 dofman->giveGlobalNumber(), 00463 dofman); 00464 } 00465 00466 // get next type record 00467 pcbuff->unpackInt(_type); 00468 } 00469 00470 00471 // unpack element data 00472 Element *elem; 00473 _partitions.resize(1); 00474 _partitions.at(1) = iproc; 00475 do { 00476 pcbuff->unpackInt(_type); 00477 if ( _type == NonlocalMaterialWTP_END_DATA ) { 00478 break; 00479 } 00480 00481 _etype = ( classType ) _type; 00482 elem = CreateUsrDefElementOfType(_etype, 0, d); 00483 elem->restoreContext(& pcDataStream, CM_Definition | CM_State); 00484 elem->setParallelMode(Element_remote); 00485 elem->setPartitionList(_partitions); 00486 d->giveTransactionManager()->addTransaction(DomainTransactionManager :: DTT_ADD, 00487 DomainTransactionManager :: DCT_Element, 00488 elem->giveGlobalNumber(), elem); 00489 } while ( 1 ); 00490 00491 return 1; 00492 } 00493 00494 /* Now the question is how to use nonlocElementDependencyMap, which is available for 00495 * each element, to quickly reinitialize nonlocal integration tables. 00496 * 00497 * if not needed, should be deleted at the end of migrate method, to free memory 00498 * 00499 * first the existing data should be cleared, and new ones initialized 00500 * profiting from nonlocElementDependencyMap, that is available for all 00501 * local elements. 00502 */ 00503 00504 void 00505 NonlocalMaterialWTP :: fastRebuildNonlocalTables() 00506 { 00507 Domain *d = lb->giveDomain(); 00508 int n, i, globnum, ie, nelem = d->giveNumberOfElements(); 00509 IntArray localElementDep; 00510 Element *elem; 00511 00512 // build nonlocal element dependency array for each element 00513 for ( ie = 1; ie <= nelem; ie++ ) { 00514 elem = d->giveElement(ie); 00515 if ( ( elem->giveParallelMode() == Element_local ) ) { 00516 IntArray localMap; 00517 // translate here nonlocElementDependencyMap[_globnum] to corresponding local numbers 00518 globnum = elem->giveGlobalNumber(); 00519 n = nonlocElementDependencyMap [ globnum ].giveSize(); 00520 localElementDep.resize(n); 00521 for ( i = 1; i <= n; i++ ) { 00522 localElementDep.at(i) = d->elementGlobal2Local( nonlocElementDependencyMap [ globnum ].at(i) ); 00523 } 00524 00525 elem->ipEvaluator(this, & NonlocalMaterialWTP :: fastElementIPNonlocTableUpdater, localElementDep); 00526 } 00527 } 00528 } 00529 00530 00531 00532 void 00533 NonlocalMaterialWTP :: fastElementIPNonlocTableUpdater(GaussPoint *gp, IntArray &map) 00534 { 00535 Element *elem = gp->giveElement(); 00536 NonlocalMaterialExtensionInterface *iface = static_cast< NonlocalMaterialExtensionInterface * >( elem->giveMaterial()->giveInterface(NonlocalMaterialExtensionInterfaceType) ); 00537 if ( iface ) { 00538 iface->rebuildNonlocalPointTable(gp, & map); 00539 } 00540 } 00541 } // end namespace oofem 00542 #endif 00543