Back to index

salome-med  6.5.0
BlockTopology.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 #include "BlockTopology.hxx"
00021 #include "MEDCouplingMemArray.hxx"
00022 #include "MEDCouplingCMesh.hxx"
00023 #include "CommInterface.hxx"
00024 #include "ProcessorGroup.hxx"
00025 #include "MPIProcessorGroup.hxx"
00026 #include "ComponentTopology.hxx"
00027 #include "InterpKernelUtilities.hxx"
00028 
00029 #include <vector>
00030 #include <algorithm>
00031 #include <utility>
00032 #include <iostream>
00033 
00034 using namespace std;
00035 
00036 namespace ParaMEDMEM
00037 {
00038 
00040   std::pair<int,int> BlockTopology::globalToLocal(const int global) const
00041   {
00042     int subdomain_id=0;
00043     int position=global;
00044     int size=_nb_elems;
00045     int size_procs=_proc_group->size();
00046     int increment=size;
00047     vector<int>axis_position(_dimension);
00048     vector<int>axis_offset(_dimension);
00049     for (int idim=0; idim<_dimension; idim++)
00050       {
00051         int axis_size=_local_array_indices[idim].size()-1;
00052         int axis_nb_elem=_local_array_indices[idim][axis_size];
00053         increment=increment/axis_nb_elem;
00054         int proc_increment = size_procs/(axis_size);
00055         int axis_pos=position/increment;
00056         position=position%increment;  
00057         int iaxis=1;
00058         while (_local_array_indices[idim][iaxis]<=axis_pos)
00059           {
00060             subdomain_id+=proc_increment;
00061             iaxis++;
00062           }
00063         axis_position[idim]=axis_pos-_local_array_indices[idim][iaxis-1];
00064         axis_offset[idim]=iaxis;
00065       }
00066     int local=0;
00067     int local_increment=1;
00068     for (int idim=_dimension-1; idim>=0; idim--)
00069       {
00070         local+=axis_position[idim]*local_increment;
00071         local_increment*=_local_array_indices[idim][axis_offset[idim]]-_local_array_indices[idim][axis_offset[idim]-1];
00072       }
00073     return make_pair(subdomain_id,local);
00074   }
00075 
00077   int BlockTopology::localToGlobal(const pair<int,int> local) const
00078   {
00079   
00080     int subdomain_id=local.first;
00081     int global=0;
00082     int loc=local.second;
00083     int increment=_nb_elems;
00084     int proc_increment=_proc_group->size();
00085     int local_increment=getNbLocalElements();
00086     for (int idim=0; idim < _dimension; idim++)
00087       {
00088         int axis_size=_local_array_indices[idim].size()-1;
00089         int axis_nb_elem=_local_array_indices[idim][axis_size];
00090         increment=axis_nb_elem==0?0:increment/axis_nb_elem;
00091         proc_increment = proc_increment/(axis_size);
00092         int proc_axis=subdomain_id/proc_increment;
00093         subdomain_id=subdomain_id%proc_increment;
00094         int local_axis_nb_elem=_local_array_indices[idim][proc_axis+1]-_local_array_indices[idim][proc_axis];
00095         local_increment = (local_axis_nb_elem==0)?0:(local_increment/local_axis_nb_elem);
00096         int iaxis=((local_increment==0)?0:(loc/local_increment))+_local_array_indices[idim][proc_axis];
00097         global+=increment*iaxis;
00098         loc = (local_increment==0)?0:(loc%local_increment);
00099       }
00100     return global;
00101   }
00102 
00103   //Retrieves the local number of elements 
00104   int BlockTopology::getNbLocalElements()const 
00105   {
00106     int position=_proc_group->myRank();
00107     int nb_elem = 1;
00108     int increment=1;
00109     for (int i=_dimension-1; i>=0; i--)
00110       {  
00111         increment *=_nb_procs_per_dim[i];
00112         int idim=position%increment;
00113         position=position/increment;
00114         int imin=_local_array_indices[i][idim];
00115         int imax=_local_array_indices[i][idim+1];
00116         nb_elem*=(imax-imin);
00117       }
00118     return nb_elem;
00119   }
00120 
00127   BlockTopology::BlockTopology(const ProcessorGroup& group, MEDCouplingCMesh *grid):
00128     _dimension(grid->getSpaceDimension()), _proc_group(&group), _owns_processor_group(false)
00129   {
00130     vector <int> axis_length(_dimension);
00131     _nb_elems=1;
00132     for (int idim=0; idim <_dimension; idim++)
00133       {
00134         DataArrayDouble *arr=grid->getCoordsAt(idim);
00135         axis_length[idim]=arr->getNbOfElems();
00136         _nb_elems*=axis_length[idim];
00137       }  
00138     //default splitting along 1st dimension
00139     _local_array_indices.resize(_dimension);
00140     _nb_procs_per_dim.resize(_dimension);
00141   
00142     _local_array_indices[0].resize(_proc_group->size()+1);
00143     _local_array_indices[0][0]=0;
00144     _nb_procs_per_dim[0]=_proc_group->size();
00145   
00146     for (int i=1; i<=_proc_group->size(); i++)
00147       {
00148         _local_array_indices[0][i]=_local_array_indices[0][i-1]+
00149           axis_length[0]/_proc_group->size();
00150         if (i<= axis_length[0]%_proc_group->size())
00151           _local_array_indices[0][i]+=1;
00152       }
00153     for (int i=1; i<_dimension; i++)
00154       {
00155         _local_array_indices[i].resize(2);
00156         _local_array_indices[i][0]=0;
00157         _local_array_indices[i][1]=axis_length[i];
00158         _nb_procs_per_dim[i]=1;
00159       }
00160     _cycle_type.resize(_dimension);
00161     for (int i=0; i<_dimension; i++)
00162       _cycle_type[i]=ParaMEDMEM::Block;  
00163   }
00164 
00174   BlockTopology::BlockTopology(const BlockTopology& geom_topo, const ComponentTopology& comp_topo):_owns_processor_group(false)
00175   {
00176     // so far, the block topology can only be created if the proc group 
00177     // is either on geom_topo or on comp_topo
00178     if (geom_topo.getProcGroup()->size()>1 && comp_topo.nbBlocks()>1)
00179       throw INTERP_KERNEL::Exception(LOCALIZED("BlockTopology cannot yet be constructed with both complex geo and components topology"));
00180 
00181     if (comp_topo.nbComponents()==1)
00182       {
00183         *this=geom_topo;
00184         return;
00185       }
00186     else
00187       {
00188         _dimension = geom_topo.getDimension()+1;
00189         if (comp_topo.nbBlocks()>1)
00190           _proc_group=comp_topo.getProcGroup();
00191         else
00192           _proc_group=geom_topo.getProcGroup();
00193         _local_array_indices=geom_topo._local_array_indices;
00194         vector<int> comp_indices = *(comp_topo.getBlockIndices());
00195         _local_array_indices.push_back(comp_indices);
00196         _nb_procs_per_dim=geom_topo._nb_procs_per_dim;
00197         _nb_procs_per_dim.push_back(comp_topo.nbBlocks());
00198         _cycle_type=geom_topo._cycle_type;
00199         _cycle_type.push_back(Block);
00200         _nb_elems=geom_topo.getNbElements()*comp_topo.nbComponents();
00201       }  
00202   }
00203 
00213   BlockTopology::BlockTopology(const ProcessorGroup& group, int nb_elem):_dimension(1),_proc_group(&group),_owns_processor_group(false)
00214   {
00215     int* nbelems_per_proc = new int[group.size()];
00216     const MPIProcessorGroup* mpi_group=dynamic_cast<const MPIProcessorGroup*>(_proc_group);
00217     const MPI_Comm* comm=mpi_group->getComm();
00218     int nbtemp=nb_elem;
00219     mpi_group->getCommInterface().allGather(&nbtemp, 1, MPI_INT, 
00220                                             nbelems_per_proc, 1, MPI_INT, 
00221                                             *comm);
00222     _nb_elems=0;  
00223   
00224     //splitting along only dimension
00225     _local_array_indices.resize(1);
00226     _nb_procs_per_dim.resize(1);  
00227           
00228     _local_array_indices[0].resize(_proc_group->size()+1);
00229     _local_array_indices[0][0]=0;
00230     _nb_procs_per_dim[0]=_proc_group->size();
00231   
00232     for (int i=1; i<=_proc_group->size(); i++)
00233       {
00234         _local_array_indices[0][i]=_local_array_indices[0][i-1]+
00235           nbelems_per_proc[i-1];
00236         _nb_elems+=nbelems_per_proc[i-1];
00237       }
00238     _cycle_type.resize(1);
00239     _cycle_type[0]=ParaMEDMEM::Block;
00240     delete[] nbelems_per_proc;
00241   }
00242 
00243   BlockTopology::~BlockTopology()
00244   {
00245     if (_owns_processor_group)
00246       delete _proc_group;
00247   }
00248 
00254   std::vector<std::pair<int,int> > BlockTopology::getLocalArrayMinMax() const
00255   {
00256     vector<pair<int,int> > local_indices (_dimension);
00257     int myrank=_proc_group->myRank();
00258     int increment=1;
00259     for (int i=_dimension-1; i>=0; i--)
00260       {  
00261         increment *=_nb_procs_per_dim[i];
00262         int idim=myrank%increment;
00263         local_indices[i].first=_local_array_indices[i][idim];
00264         local_indices[i].second=_local_array_indices[i][idim+1];
00265         cout << local_indices[i].first << " "<< local_indices[i].second<<endl;
00266       }
00267     return local_indices;
00268   }
00269 
00272   void BlockTopology::serialize(int* & serializer, int& size) const 
00273   {
00274     vector<int> buffer;
00275   
00276     buffer.push_back(_dimension);
00277     buffer.push_back(_nb_elems);
00278     for (int i=0; i<_dimension; i++)
00279       {
00280         buffer.push_back(_nb_procs_per_dim[i]);
00281         buffer.push_back(_cycle_type[i]);
00282         buffer.push_back(_local_array_indices[i].size());
00283         for (int j=0; j<(int)_local_array_indices[i].size(); j++)
00284           buffer.push_back(_local_array_indices[i][j]);
00285       }
00286   
00287     //serializing the comm group
00288     int size_comm=_proc_group->size();
00289     buffer.push_back(size_comm);
00290     MPIProcessorGroup world_group(_proc_group->getCommInterface());
00291     for (int i=0; i<size_comm;i++)
00292       {
00293         int world_rank=world_group.translateRank(_proc_group, i);
00294         buffer.push_back(world_rank);
00295       }
00296   
00297     serializer=new int[buffer.size()];
00298     size=buffer.size();
00299     copy(buffer.begin(), buffer.end(), serializer);
00300   }
00301 
00308   void BlockTopology::unserialize(const int* serializer,const CommInterface& comm_interface)
00309   {
00310     const int* ptr_serializer=serializer;
00311     cout << "unserialize..."<<endl;
00312     _dimension=*(ptr_serializer++);
00313     cout << "dimension "<<_dimension<<endl;
00314     _nb_elems=*(ptr_serializer++);
00315     cout << "nbelems "<<_nb_elems<<endl;
00316     _nb_procs_per_dim.resize(_dimension);
00317     _cycle_type.resize(_dimension);
00318     _local_array_indices.resize(_dimension);
00319     for (int i=0; i<_dimension; i++)
00320       {
00321         _nb_procs_per_dim[i]=*(ptr_serializer++);
00322         _cycle_type[i]=(CYCLE_TYPE)*(ptr_serializer++);
00323         _local_array_indices[i].resize(*(ptr_serializer++));
00324         for (int j=0; j<(int)_local_array_indices[i].size(); j++)
00325           _local_array_indices[i][j]=*(ptr_serializer++);
00326       }
00327     set<int> procs;
00328     int size_comm=*(ptr_serializer++);
00329     for (int i=0; i<size_comm; i++)
00330       procs.insert(*(ptr_serializer++));
00331     cout << "unserialize..."<<procs.size()<<endl;
00332     _proc_group=new MPIProcessorGroup(comm_interface,procs);
00333     _owns_processor_group=true;
00334     //TODO manage memory ownership of _proc_group  
00335   }
00336 }