+ * \return MEDCouplingFieldDouble * - a field on cells that the caller has to deal with (deallocate it).
+ *
+ * \sa buildCellFieldOnWithGhost
+ */
+MEDCouplingFieldDouble *MEDCouplingAMRAttribute::buildCellFieldOnWithoutGhost(MEDCouplingCartesianAMRMeshGen *mesh, const std::string& fieldName) const
+{
+ const DataArrayDouble *arr(0);
+ for(std::vector< MCAuto<MEDCouplingGridCollection> >::const_iterator it=_levs.begin();it!=_levs.end();it++)
+ {
+ int tmp(-1);
+ if((*it)->presenceOf(mesh,tmp))
+ {
+ const DataArrayDoubleCollection& ddc((*it)->getFieldsAt(tmp));
+ arr=ddc.getFieldWithName(fieldName);
+ }
+ }
+ if(!arr)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::buildCellFieldOnWithoutGhost : the mesh specified is not in the progeny of this !");
+ //
+ MCAuto<MEDCouplingIMesh> im(mesh->getImageMesh()->buildWithGhost(_ghost_lev));
+ std::vector<int> cgs(mesh->getImageMesh()->getCellGridStructure()),cgsWG(im->getCellGridStructure());
+ MCAuto<DataArrayDouble> arr2(DataArrayDouble::New());
+ arr2->alloc(mesh->getImageMesh()->getNumberOfCells(),arr->getNumberOfComponents());
+ std::vector< std::pair<int,int> > cgs2(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(cgs));
+ MEDCouplingStructuredMesh::ApplyGhostOnCompactFrmt(cgs2,_ghost_lev);
+ std::vector<int> fakeFactors(mesh->getImageMesh()->getSpaceDimension(),1);
+ MEDCouplingIMesh::SpreadCoarseToFine(arr,cgsWG,arr2,cgs2,fakeFactors);
+ arr2->copyStringInfoFrom(*arr);
+ //
+ MCAuto<MEDCouplingFieldDouble> ret(MEDCouplingFieldDouble::New(ON_CELLS));
+ ret->setMesh(mesh->getImageMesh());
+ ret->setArray(arr2);
+ ret->setName(arr->getName());
+ return ret.retn();
+}
+
+
+std::string MEDCouplingAMRAttribute::writeVTHB(const std::string& fileName) const
+{
+ static const char EXT[]=".vthb";
+ std::string baseName,extName,zeFileName;
+ MEDCouplingMesh::SplitExtension(fileName,baseName,extName);
+ if(extName==EXT)
+ zeFileName=fileName;
+ else
+ { zeFileName=baseName; zeFileName+=EXT; }
+ //
+ std::ofstream ofs(fileName.c_str());
+ ofs << "<VTKFile type=\"vtkOverlappingAMR\" version=\"1.1\" byte_order=\"" << MEDCouplingByteOrderStr() << "\">\n";
+ const MEDCouplingCartesianAMRMesh *gf(getMyGodFather());
+ ofs << " <vtkOverlappingAMR origin=\"";
+ const MEDCouplingIMesh *gfm(gf->getImageMesh());
+ std::vector<double> orig(gfm->getOrigin());
+ std::vector<double> spacing(gfm->getDXYZ());
+ int dim((int)orig.size());
+ std::copy(orig.begin(),orig.end(),std::ostream_iterator<double>(ofs," ")); ofs << "\" grid_description=\"";
+ for(int i=0;i<dim;i++)
+ {
+ char tmp[2]; tmp[0]='X'+i; tmp[1]='\0';
+ ofs << tmp;
+ }
+ ofs << "\">\n";
+ //
+ int maxLev(gf->getMaxNumberOfLevelsRelativeToThis()),kk(0);
+ for(int i=0;i<maxLev;i++)
+ {
+ std::vector<MEDCouplingCartesianAMRPatchGen *> patches(gf->retrieveGridsAt(i));
+ std::size_t sz(patches.size());
+ std::vector< MCAuto<MEDCouplingCartesianAMRPatchGen> > patchesSafe(sz);
+ for(std::size_t j=0;j<sz;j++)
+ patchesSafe[j]=patches[j];
+ if(sz==0)
+ continue;
+ ofs << " <Block level=\"" << i << "\" spacing=\"";
+ std::copy(spacing.begin(),spacing.end(),std::ostream_iterator<double>(ofs," "));
+ ofs << "\">\n";
+ if(i!=maxLev-1)
+ {
+ std::vector<int> factors(patches[0]->getMesh()->getFactors());
+ for(int k=0;k<dim;k++)
+ spacing[k]*=1./((double) factors[k]);
+ }
+ std::size_t jj(0);
+ for(std::vector<MEDCouplingCartesianAMRPatchGen *>::const_iterator it=patches.begin();it!=patches.end();it++,jj++,kk++)
+ {
+ ofs << " <DataSet index=\"" << jj << "\" amr_box=\"";
+ const MEDCouplingCartesianAMRPatch *patchCast(dynamic_cast<const MEDCouplingCartesianAMRPatch *>(*it));
+ const MEDCouplingCartesianAMRMeshGen *mesh((*it)->getMesh());
+ if(patchCast)
+ {
+ const std::vector< std::pair<int,int> >& bltr(patchCast->getBLTRRangeRelativeToGF());
+ for(int pp=0;pp<dim;pp++)
+ ofs << bltr[pp].first << " " << bltr[pp].second-1 << " ";
+ }
+ else
+ {
+ const MEDCouplingIMesh *im((*it)->getMesh()->getImageMesh());
+ std::vector<int> cgs(im->getCellGridStructure());
+ for(int pp=0;pp<dim;pp++)
+ ofs << "0 " << cgs[pp]-1 << " ";
+ }
+ ofs << "\" file=\"";
+ //
+ int tmp(-1);
+ if(_levs[i]->presenceOf((*it)->getMesh(),tmp))
+ {
+ const DataArrayDoubleCollection& ddc(_levs[i]->getFieldsAt(tmp));
+ std::vector<DataArrayDouble *> arrs(ddc.retrieveFields());
+ std::size_t nbFields(arrs.size());
+ std::vector< MCAuto<DataArrayDouble> > arrsSafe(nbFields),arrs2Safe(nbFields);
+ std::vector< const MEDCouplingFieldDouble *> fields(nbFields);
+ std::vector< MCAuto<MEDCouplingFieldDouble> > fieldsSafe(nbFields);
+ for(std::size_t pp=0;pp<nbFields;pp++)
+ arrsSafe[pp]=arrs[pp];
+ for(std::size_t pp=0;pp<nbFields;pp++)
+ {
+ MCAuto<MEDCouplingIMesh> im(mesh->getImageMesh()->buildWithGhost(_ghost_lev));
+ std::vector<int> cgs(mesh->getImageMesh()->getCellGridStructure()),cgsWG(im->getCellGridStructure());
+ arrs2Safe[pp]=DataArrayDouble::New();
+ arrs2Safe[pp]->alloc(mesh->getImageMesh()->getNumberOfCells(),arrs[pp]->getNumberOfComponents());
+ std::vector< std::pair<int,int> > cgs2(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(cgs));
+ MEDCouplingStructuredMesh::ApplyGhostOnCompactFrmt(cgs2,_ghost_lev);
+ std::vector<int> fakeFactors(mesh->getImageMesh()->getSpaceDimension(),1);
+ MEDCouplingIMesh::SpreadCoarseToFine(arrs[pp],cgsWG,arrs2Safe[pp],cgs2,fakeFactors);
+ arrs2Safe[pp]->copyStringInfoFrom(*arrs[pp]);
+ //
+ fieldsSafe[pp]=MEDCouplingFieldDouble::New(ON_CELLS); fields[pp]=fieldsSafe[pp];
+ fieldsSafe[pp]->setMesh(mesh->getImageMesh());
+ fieldsSafe[pp]->setArray(arrs2Safe[pp]);
+ fieldsSafe[pp]->setName(arrs[pp]->getName());
+ }
+ std::ostringstream vtiFileName; vtiFileName << baseName << "_" << kk << ".vti";
+ MEDCouplingFieldDouble::WriteVTK(vtiFileName.str(),fields,true);
+ //
+ ofs << vtiFileName.str() << "\">\n";
+ ofs << " \n </DataSet>\n";
+ }
+ }
+ ofs << " </Block>\n";
+ }
+ //
+ ofs << " </vtkOverlappingAMR>\n";
+ ofs << "</VTKFile>\n";
+ return zeFileName;
+}
+
+ /*!
+ * This method is useful just after a remesh after a time step computation to project values in \a this to the new
+ * mesh \a targetGF.
+ *
+ * This method performs a projection from \a this to a target AMR mesh \a targetGF.
+ * This method performs the projection by trying to transfer the finest information to \a targetGF.
+ * \b WARNING this method does not update the ghost zone, if any.
+ * The level0 of \a this god father must have the same structure than those of \a targetGF.
+ *
+ * This method makes checks that ghost size of \a this and \a targetGF are the same, and that
+ * the number of levels in \a this and in \a targetGF are also the same.
+ */
+MEDCouplingAMRAttribute *MEDCouplingAMRAttribute::projectTo(MEDCouplingCartesianAMRMesh *targetGF) const
+{
+ if(!targetGF)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : given other target god is NULL !");
+ if(_levs.empty())
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : no levels in this !");
+ const MEDCouplingGridCollection *lev0(_levs[0]);
+ if(!lev0)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : lev0 is NULL !");
+ std::vector< std::pair < std::string, std::vector<std::string> > > fieldNames(lev0->getInfoOnComponents());
+ MCAuto<MEDCouplingAMRAttribute> ret(MEDCouplingAMRAttribute::New(targetGF,fieldNames,_ghost_lev));
+ ret->spillNatures(lev0->getNatures());
+ ret->alloc();
+ int nbLevs(getNumberOfLevels());
+ if(targetGF->getMaxNumberOfLevelsRelativeToThis()!=nbLevs)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : number of levels of this and targetGF must be the same !");
+ // first step copy level0
+ if(getMyGodFather()->getImageMesh()->getCellGridStructure()!=targetGF->getImageMesh()->getCellGridStructure())
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : god father of this and target ones do not have the same structure !");
+ const DataArrayDoubleCollection& col(lev0->getFieldsAt(0));
+ DataArrayDoubleCollection& colTarget(ret->_levs[0]->getFieldsAt(0));
+ colTarget.copyFrom(col);
+ // then go deeper and deeper
+ for(int i=1;i<nbLevs;i++)
+ {
+ ret->synchronizeCoarseToFineByOneLevel(i-1);
+ MEDCouplingGridCollection *targetCol(ret->_levs[i]);
+ if(!targetCol)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : null lev of target !");
+ const MEDCouplingGridCollection *thisCol(_levs[i]);
+ if(!thisCol)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::projectTo : null lev of this !");
+ targetCol->copyOverlappedZoneFrom(_ghost_lev,*thisCol);
+ }
+ return ret.retn();
+}
+
+/*!
+ * This method synchronizes from fine to coarse direction arrays. This method makes the hypothesis that \a this has been allocated before using
+ * MEDCouplingAMRAttribute::alloc method.
+ * This method \b DOES \b NOT \b UPDATE the ghost zones (neither the fine not the coarse)
+ *
+ * \sa synchronizeFineToCoarseBetween
+ */
+void MEDCouplingAMRAttribute::synchronizeFineToCoarse()
+{
+ if(_levs.empty())
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarse : not any levels in this !");
+ std::size_t sz(_levs.size());
+ //
+ while(sz>1)
+ {
+ sz--;
+ synchronizeFineToCoarseByOneLevel((int)sz);
+ }
+}
+
+/*!
+ * This method allows to synchronizes fields on fine patches on level \a fromLev to coarser patches at \a toLev level.
+ * This method operates step by step performing the synchronization the \a fromLev to \a fromLev - 1, then \a fromLev -1 to \a fromLev - 2 ...
+ * until reaching \a toLev level.
+ * This method \b DOES \b NOT \b UPDATE the ghost zones (neither the fine not the coarse).
+ *
+ * \param [in] fromLev - an existing level considered as fine so bigger than \a toLev
+ * \param [in] toLev - an existing level considered as the target level to reach.
+ *
+ */
+void MEDCouplingAMRAttribute::synchronizeFineToCoarseBetween(int fromLev, int toLev)
+{
+ int nbl(getNumberOfLevels());
+ if(fromLev<0 || toLev<0 || fromLev>=nbl || toLev>=nbl)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarseBetween : fromLev and toLev must be >= 0 and lower than number of levels in this !");
+ if(fromLev==toLev)
+ return ;//nothing to do
+ if(fromLev<toLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineToCoarseBetween : the fromLev level is lower than toLev level ! Call synchronizeFineToCoarseBetween ");
+ for(int i=fromLev;i>toLev;i--)
+ synchronizeFineToCoarseByOneLevel(i);
+}
+
+/*!
+ * This method synchronizes from coarse to fine arrays and fine to fine each other (if _ghost_lev is >0). This method makes the hypothesis that \a this has been allocated before using
+ * MEDCouplingAMRAttribute::alloc method.
+ * This method \b DOES \b UPDATE \b the \b ghost \b zone (contrary to synchronizeFineToCoarse method)
+ */
+void MEDCouplingAMRAttribute::synchronizeCoarseToFine()
+{
+ if(_levs.empty())
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeCoarseToFine : not any levels in this !");
+ std::size_t sz(_levs.size());
+ //
+ for(std::size_t i=0;i<sz-1;i++)
+ synchronizeCoarseToFineByOneLevel((int)i);
+}
+
+/*!
+ * This method allows to synchronizes fields on coarse patches on level \a fromLev to their respective refined patches at \a toLev level.
+ * This method operates step by step performing the synchronization the \a fromLev to \a fromLev + 1, then \a fromLev + 1 to \a fromLev + 2 ...
+ * until reaching \a toLev level.
+ * This method \b DOES \b UPDATE \b the \b ghost \b zone (contrary to synchronizeFineToCoarseBetween method)
+ *
+ * \param [in] fromLev - an existing level considered as coarse so lower than \a toLev
+ * \param [in] toLev - an existing level considered as the target level to reach.
+ */
+void MEDCouplingAMRAttribute::synchronizeCoarseToFineBetween(int fromLev, int toLev)
+{
+ int nbl(getNumberOfLevels());
+ if(fromLev<0 || toLev<0 || fromLev>=nbl || toLev>=nbl)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeCoarseToFineBetween : fromLev and toLev must be >= 0 and lower than number of levels in this !");
+ if(fromLev==toLev)
+ return ;//nothing to do
+ if(fromLev>toLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeCoarseToFineBetween : the fromLev level is greater than toLev level ! Call synchronizeFineToCoarseBetween instead !");
+ for(int i=fromLev;i<toLev;i++)
+ synchronizeCoarseToFineByOneLevel(i);
+}
+
+/*!
+ * This method synchronizes the ghost zone of all patches (excepted the god father one).
+ * This method operates in 4 steps. Larger is the number of steps more accurate is the information in the ghost zone.
+ *
+ * - firstly coarse to fine with no interactions between brother patches.
+ * - secondly connected brother patches in a same master patch are updated.
+ * - thirdly connected nephew patches are updated each other.
+ * - forthly nth generation cousin patches are updated each other.
+ *
+ * This method makes the hypothesis that \a this has been allocated before using MEDCouplingAMRAttribute::alloc method.
+ * So if \a _ghost_lev == 0 this method has no effect.
+ */
+void MEDCouplingAMRAttribute::synchronizeAllGhostZones()
+{
+ int sz(getNumberOfLevels());
+ if(sz==0)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineEachOther : not any levels in this !");
+ // 1st - synchronize from coarse to the finest all the patches (excepted the god father one)
+ for(int i=1;i<sz;i++)
+ {
+ const MEDCouplingGridCollection *fine(_levs[i]),*coarse(_levs[i-1]);
+ MEDCouplingGridCollection::SynchronizeCoarseToFineOnlyInGhostZone(_ghost_lev,coarse,fine);
+ }
+ // 2nd - classical direct sublevel inside common patch
+ for(int i=1;i<sz;i++)
+ {
+ const MEDCouplingGridCollection *curLev(_levs[i]);
+ if(!curLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeFineEachOtherInGhostZone : presence of a NULL element !");
+ curLev->synchronizeFineEachOther(_ghost_lev,_neighbors[i]);
+ }
+ // 3rd - mixed level
+ for(std::vector< std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *> >::const_iterator it=_mixed_lev_neighbors.begin();it!=_mixed_lev_neighbors.end();it++)
+ {
+ const DataArrayDoubleCollection *firstDAC(&findCollectionAttachedTo((*it).first->getMesh())),*secondDAC(&findCollectionAttachedTo((*it).second->getMesh()));
+ DataArrayDoubleCollection::SynchronizeGhostZoneOfOneUsingTwo(_ghost_lev,(*it).first,firstDAC,(*it).second,secondDAC);
+ }
+ // 4th - same level but with far ancestor.
+ for(int i=1;i<sz;i++)
+ {
+ const MEDCouplingGridCollection *fine(_levs[i]);
+ fine->synchronizeFineEachOtherExt(_ghost_lev,_cross_lev_neighbors[i]);
+ }
+}
+
+/*!
+ * This method works \b ONLY \b ON \b DIRECT \b SONS \b OF \a mesh. So only a part of patches at a given level is updated here.
+ * The ghost zone of all of these sons of \a mesh are updated using the brother patches (the patches sharing the \b SAME \a mesh).
+ * It is sometimes possible that a ghost zone of some sons of \a mesh are covered by a patch of same level but different father.
+ * For such cases, the ghost zones are \b NOT updated. If you need a more thorough (but more costly) ghost zone update use synchronizeAllGhostZonesAtASpecifiedLevel method instead.
+ *
+ * \param [in] mesh - an element in the progeny of god father in \a this, which the ghost zone of its sons will be updated each other.
+ *
+ */
+void MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf(const MEDCouplingCartesianAMRMeshGen *mesh)
+{
+ if(!mesh)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf : input mesh is NULL !");
+ int level(mesh->getAbsoluteLevelRelativeTo(_gf)),sz(getNumberOfLevels());
+ if(level<0 || level>=sz-1)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf : the specified level does not exist ! Must be in [0,nbOfLevelsOfThis-1) !");
+ const std::vector< std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *> >& itemsToFilter(_neighbors[level+1]);
+ std::vector< std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *> > itemsToSync; itemsToSync.reserve(itemsToFilter.size());
+ for(std::vector< std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *> >::const_iterator it=itemsToFilter.begin();it!=itemsToFilter.end();it++)
+ {
+ if((*it).first->getMesh()->getFather()==mesh && (*it).second->getMesh()->getFather()==mesh)
+ itemsToSync.push_back(std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *>((*it).first,(*it).second));
+ }
+ const MEDCouplingGridCollection *curLev(_levs[level+1]);
+ if(!curLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesOfDirectChidrenOf : presence of a NULL element !");
+ curLev->synchronizeFineEachOther(_ghost_lev,itemsToSync);
+}
+
+/*!
+ * This method updates \b all the patches at level \a level each other without consideration of their father.
+ * So this method is more time consuming than synchronizeAllGhostZonesOfDirectChidrenOf.
+ */
+void MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevel(int level)
+{
+ int maxLev(getNumberOfLevels());
+ if(level<0 || level>=maxLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevel : the specified level must be in [0,maxLevel) !");
+ if(level==0)
+ return ;//at level 0 only one patch -> no need to update
+ // 1st step - updates all patches pairs at level \a level sharing the same father
+ const std::vector< std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *> >& items(_neighbors[level]);
+ const MEDCouplingGridCollection *curLev(_levs[level]);
+ if(!curLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevel : presence of a NULL element !");
+ curLev->synchronizeFineEachOther(_ghost_lev,items);
+ //2nd step - updates all patches pairs at level \a level not sharing the same father
+ const std::vector< std::pair<const MEDCouplingCartesianAMRPatch *,const MEDCouplingCartesianAMRPatch *> >& items2(_cross_lev_neighbors[level]);
+ curLev->synchronizeFineEachOtherExt(_ghost_lev,items2);
+}
+
+/*!
+ * This method updates ghost zones of patches at level \a level whatever their father \b using \b father \b patches \b ONLY (at level \b level - 1).
+ * This method is useful to propagate to the ghost zone of childhood the modification.
+ */
+void MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevelUsingOnlyFather(int level)
+{
+ int maxLev(getNumberOfLevels());
+ if(level<=0 || level>=maxLev)
+ throw INTERP_KERNEL::Exception("MEDCouplingAMRAttribute::synchronizeAllGhostZonesAtASpecifiedLevelUsingOnlyFather : the specified level must be in (0,maxLevel) !");
+ const MEDCouplingGridCollection *fine(_levs[level]),*coarse(_levs[level-1]);
+ MEDCouplingGridCollection::SynchronizeCoarseToFineOnlyInGhostZone(_ghost_lev,coarse,fine);
+ //_cross_lev_neighbors is not needed.
+}
+
+/*!
+ * This method allocates all DataArrayDouble instances stored recursively in \a this.