OOFEM  2.1
nonlocalmatwtp.C
Go to the documentation of this file.
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 

This page is part of the OOFEM documentation. Copyright (c) 2011 Borek Patzak
Project e-mail: info@oofem.org
Generated at Sun Mar 10 2013 18:16:55 for OOFEM by doxygen 1.7.6.1 written by Dimitri van Heesch, © 1997-2011