X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;ds=sidebyside;f=src%2FMEDCoupling%2FMEDCouplingCartesianAMRMesh.cxx;h=ced42519c8b0afb8d42aba209467dcc4d43aa257;hb=e33d5b1e5851364c5daa5f9413ea6b29310ee15e;hp=0960420631fe4c55ff51c3b0db6aa5c6b4496911;hpb=d617787e44d1c1f9ef14a5f46d918542c108aba9;p=tools%2Fmedcoupling.git diff --git a/src/MEDCoupling/MEDCouplingCartesianAMRMesh.cxx b/src/MEDCoupling/MEDCouplingCartesianAMRMesh.cxx index 096042063..ced42519c 100644 --- a/src/MEDCoupling/MEDCouplingCartesianAMRMesh.cxx +++ b/src/MEDCoupling/MEDCouplingCartesianAMRMesh.cxx @@ -19,6 +19,7 @@ // Author : Anthony Geay #include "MEDCouplingCartesianAMRMesh.hxx" +#include "MEDCouplingFieldDouble.hxx" #include "MEDCoupling1GTUMesh.hxx" #include "MEDCouplingIMesh.hxx" #include "MEDCouplingUMesh.hxx" @@ -53,6 +54,22 @@ MEDCouplingCartesianAMRPatchGen::MEDCouplingCartesianAMRPatchGen(MEDCouplingCart _mesh=mesh; _mesh->incrRef(); } +const MEDCouplingCartesianAMRMeshGen *MEDCouplingCartesianAMRPatchGen::getMeshSafe() const +{ + const MEDCouplingCartesianAMRMeshGen *mesh(_mesh); + if(!mesh) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatchGen::getMeshSafe const : the mesh is NULL !"); + return mesh; +} + +MEDCouplingCartesianAMRMeshGen *MEDCouplingCartesianAMRPatchGen::getMeshSafe() +{ + MEDCouplingCartesianAMRMeshGen *mesh(_mesh); + if(!mesh) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatchGen::getMeshSafe : the mesh is NULL !"); + return mesh; +} + std::vector MEDCouplingCartesianAMRPatchGen::getDirectChildren() const { std::vector ret; @@ -73,6 +90,11 @@ MEDCouplingCartesianAMRPatch::MEDCouplingCartesianAMRPatch(MEDCouplingCartesianA throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch constructor : space dimension of father and input bottomLeft/topRight size mismatches !"); } +void MEDCouplingCartesianAMRPatch::addPatch(const std::vector< std::pair >& bottomLeftTopRight, const std::vector& factors) +{ + return getMeshSafe()->addPatch(bottomLeftTopRight,factors); +} + int MEDCouplingCartesianAMRPatch::getNumberOfOverlapedCellsForFather() const { return MEDCouplingStructuredMesh::DeduceNumberOfGivenRangeInCompactFrmt(_bl_tr); @@ -80,7 +102,8 @@ int MEDCouplingCartesianAMRPatch::getNumberOfOverlapedCellsForFather() const /*! * This method states if \a other patch is in the neighborhood of \a this. The neighborhood zone is defined by \a ghostLev parameter - * the must be >= 0. + * the must be >= 0. \b WARNING this method only works if \a this and \a other share the same father (no check of this will be done !). + * Call isInMyNeighborhoodExt to deal with 2 patches not sharing directly the same father. * * \param [in] other - The other patch * \param [in] ghostLev - The size of the neighborhood zone. @@ -88,6 +111,8 @@ int MEDCouplingCartesianAMRPatch::getNumberOfOverlapedCellsForFather() const * \throw if \a this or \a other are invalid (end before start). * \throw if \a ghostLev is \b not >= 0 . * \throw if \a this and \a other have not the same space dimension. + * + * \sa isInMyNeighborhoodExt */ bool MEDCouplingCartesianAMRPatch::isInMyNeighborhood(const MEDCouplingCartesianAMRPatch *other, int ghostLev) const { @@ -97,13 +122,54 @@ bool MEDCouplingCartesianAMRPatch::isInMyNeighborhood(const MEDCouplingCartesian throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::isInMyNeighborhood : the input patch is NULL !"); const std::vector< std::pair >& thisp(getBLTRRange()); const std::vector< std::pair >& otherp(other->getBLTRRange()); - std::size_t thispsize(thisp.size()); - if(thispsize!=otherp.size()) + return IsInMyNeighborhood(ghostLev,thisp,otherp); +} + +/*! + * This method states if \a other patch is in the neighborhood of \a this. The neighborhood zone is defined by \a ghostLev parameter + * the must be >= 0. This method works even if \a this and \a other does not share the same father. + * + * \param [in] other - The other patch + * \param [in] ghostLev - The size of the neighborhood zone. + * + * \throw if \a this or \a other are invalid (end before start). + * \throw if \a ghostLev is \b not >= 0 . + * \throw if \a this and \a other have not the same space dimension. + * \throw if there is not common ancestor of \a this and \a other. + * + * \sa isInMyNeighborhood + */ +bool MEDCouplingCartesianAMRPatch::isInMyNeighborhoodExt(const MEDCouplingCartesianAMRPatch *other, int ghostLev) const +{ + if(ghostLev<0) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::isInMyNeighborhoodExt : the size of the neighborhood must be >= 0 !"); + if(!other) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::isInMyNeighborhoodExt : the input patch is NULL !"); + int lev; + const MEDCouplingCartesianAMRMeshGen *com(FindCommonAncestor(this,other,lev));//check that factors are OK + if(lev==0) + return isInMyNeighborhood(other,ghostLev); + std::vector offset(ComputeOffsetFromTwoToOne(com,lev,this,other)); + const std::vector< std::pair >& thisp(getBLTRRange()); + std::vector< std::pair > otherp(other->getBLTRRange()); + std::size_t sz(offset.size()); + for(std::size_t i=0;i >& p1, const std::vector< std::pair >& p2) +{ + std::size_t thispsize(p1.size()); + if(thispsize!=p2.size()) throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::isInMyNeighborhood : the dimensions must be the same !"); for(std::size_t i=0;i& thispp(thisp[i]); - const std::pair& otherpp(otherp[i]); + const std::pair& thispp(p1[i]); + const std::pair& otherpp(p2[i]); if(thispp.second > > MEDCouplingCartesianAMRPatch::FindNeighborsOfSubPatchesOf(int ghostLev, const MEDCouplingCartesianAMRPatch *p1, const MEDCouplingCartesianAMRPatch *p2) +{ + if(!p1 || !p2) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::FindNeighborsOfSubPatchesOf : the input pointers must be not NULL !"); + std::vector< std::vector< std::pair > > ret; + std::vector< const MEDCouplingCartesianAMRPatch *> p1Work(p1->getMesh()->getPatches()),p2Work(p2->getMesh()->getPatches()); + while(!p1Work.empty()) + { + std::vector< std::pair > retTmp; + std::vector p1Work2,p2Work2; + for(std::vector::const_iterator it1=p1Work.begin();it1!=p1Work.end();it1++) + { + for(std::vector::const_iterator it2=p2Work.begin();it2!=p2Work.end();it2++) + { + if((*it1)->isInMyNeighborhoodExt(*it2,ghostLev)) + retTmp.push_back(std::pair(*it1,*it2)); + } + std::vector tmp1((*it1)->getMesh()->getPatches()); + p1Work2.insert(p1Work2.end(),tmp1.begin(),tmp1.end()); + } + for(std::vector::const_iterator it2=p2Work.begin();it2!=p2Work.end();it2++) + { + std::vector tmp2((*it2)->getMesh()->getPatches()); + p2Work2.insert(p2Work2.end(),tmp2.begin(),tmp2.end()); + } + ret.push_back(retTmp); + p1Work=p1Work2; + p2Work=p2Work2; + } + return ret; +} + +/*! + * \a p1 and \a p2 are expected to be neighbors (inside the \a ghostLev zone). This method updates \a dataOnP1 only in the ghost part using a part of \a dataOnP2. + * + * \saUpdateNeighborsOfOneWithTwoExt + */ +void MEDCouplingCartesianAMRPatch::UpdateNeighborsOfOneWithTwo(int ghostLev, const std::vector& factors, const MEDCouplingCartesianAMRPatch *p1, const MEDCouplingCartesianAMRPatch *p2, DataArrayDouble *dataOnP1, const DataArrayDouble *dataOnP2) +{ + const std::vector< std::pair >& p1BLTR(p1->getBLTRRange()); + const std::vector< std::pair >& p2BLTR(p2->getBLTRRange()); + UpdateNeighborsOfOneWithTwoInternal(ghostLev,factors,p1BLTR,p2BLTR,dataOnP1,dataOnP2); +} + +void MEDCouplingCartesianAMRPatch::UpdateNeighborsOfOneWithTwoInternal(int ghostLev, const std::vector& factors, const std::vector< std::pair >&p1 ,const std::vector< std::pair >&p2, DataArrayDouble *dataOnP1, const DataArrayDouble *dataOnP2) +{//p1=[(1,4),(2,4)] p2=[(4,5),(3,4)] + int dim((int)factors.size()); + std::vector dimsCoarse(MEDCouplingStructuredMesh::GetDimensionsFromCompactFrmt(p1));//[3,2] + std::transform(dimsCoarse.begin(),dimsCoarse.end(),factors.begin(),dimsCoarse.begin(),std::multiplies());//[12,8] + std::transform(dimsCoarse.begin(),dimsCoarse.end(),dimsCoarse.begin(),std::bind2nd(std::plus(),2*ghostLev));//[14,10] + std::vector< std::pair > rangeCoarse(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(dimsCoarse));//[(0,14),(0,10)] + std::vector fakeFactors(dim,1); + // + std::vector< std::pair > tmp0,tmp1,tmp2; + MEDCouplingStructuredMesh::ChangeReferenceFromGlobalOfCompactFrmt(p1,p2,tmp0,false);//tmp0=[(3,4),(1,2)] + ApplyFactorsOnCompactFrmt(tmp0,factors);//tmp0=[(12,16),(4,8)] + ApplyGhostOnCompactFrmt(tmp0,ghostLev);//tmp0=[(13,17),(5,9)] + std::vector< std::pair > interstRange(MEDCouplingStructuredMesh::IntersectRanges(tmp0,rangeCoarse));//interstRange=[(13,14),(5,9)] + MEDCouplingStructuredMesh::ChangeReferenceFromGlobalOfCompactFrmt(p2,p1,tmp1,false);//tmp1=[(-3,0),(-1,1)] + ApplyFactorsOnCompactFrmt(tmp1,factors);//tmp1=[(-12,-4),(-4,0)] + MEDCouplingStructuredMesh::ChangeReferenceToGlobalOfCompactFrmt(tmp1,interstRange,tmp2,false);//tmp2=[(1,2),(1,5)] + // + std::vector< std::pair > dimsFine(p2); + ApplyFactorsOnCompactFrmt(dimsFine,factors); + ApplyAllGhostOnCompactFrmt(dimsFine,ghostLev); + // + MEDCouplingAutoRefCountObjectPtr ghostVals(MEDCouplingStructuredMesh::ExtractFieldOfDoubleFrom(MEDCouplingStructuredMesh::GetDimensionsFromCompactFrmt(dimsFine),dataOnP2,tmp2)); + MEDCouplingIMesh::CondenseFineToCoarse(dimsCoarse,ghostVals,interstRange,fakeFactors,dataOnP1); +} + +/*! + * Idem than UpdateNeighborsOfOneWithTwo, except that here \a p1 and \a p2 are not sharing the same direct father. + * + * \sa UpdateNeighborsOfOneWithTwo + */ +void MEDCouplingCartesianAMRPatch::UpdateNeighborsOfOneWithTwoExt(int ghostLev, const MEDCouplingCartesianAMRPatch *p1, const MEDCouplingCartesianAMRPatch *p2, DataArrayDouble *dataOnP1, const DataArrayDouble *dataOnP2) +{ + const std::vector< std::pair >& p1BLTR(p1->getBLTRRange());//p1BLTR=[(10,12),(5,8)] + std::vector< std::pair > p2BLTR(p2->getBLTRRange());//p2BLTR=[(0,1),(0,5)] + int lev(0); + const MEDCouplingCartesianAMRMeshGen *ca(FindCommonAncestor(p1,p2,lev)); + std::vector offset(ComputeOffsetFromTwoToOne(ca,lev,p1,p2));//[12,4] + p2BLTR=MEDCouplingStructuredMesh::TranslateCompactFrmt(p2BLTR,offset);//p2BLTR=[(12,13),(4,9)] + UpdateNeighborsOfOneWithTwoInternal(ghostLev,p1->getMesh()->getFather()->getFactors(),p1BLTR,p2BLTR,dataOnP1,dataOnP2); +} + std::size_t MEDCouplingCartesianAMRPatch::getHeapMemorySizeWithoutChildren() const { std::size_t ret(sizeof(MEDCouplingCartesianAMRPatch)); @@ -126,6 +278,108 @@ std::size_t MEDCouplingCartesianAMRPatch::getHeapMemorySizeWithoutChildren() con return ret; } +const MEDCouplingCartesianAMRMeshGen *MEDCouplingCartesianAMRPatch::FindCommonAncestor(const MEDCouplingCartesianAMRPatch *p1, const MEDCouplingCartesianAMRPatch *p2, int& lev) +{ + const MEDCouplingCartesianAMRMeshGen *f1(p1->_mesh),*f2(p2->_mesh); + lev=0; + while(f1!=f2 || f1==0 || f2==0) + { + f1=f1->getFather(); f2=f2->getFather(); + if(f1->getFactors()!=f2->getFactors()) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::FindCommonAncestor : factors differ !"); + lev++; + } + if(f1!=f2) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::FindCommonAncestor : no common ancestor between p1 and p2 !"); + return f1; +} + +std::vector MEDCouplingCartesianAMRPatch::ComputeOffsetFromTwoToOne(const MEDCouplingCartesianAMRMeshGen *comAncestor, int lev, const MEDCouplingCartesianAMRPatch *p1, const MEDCouplingCartesianAMRPatch *p2) +{ + if(lev<=0) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::ComputeOffsetFromTwoToOne : this method is useful only for lev > 0 !"); + int zeLev(lev-1); + int dim(p1->getMesh()->getSpaceDimension()); + if(p2->getMesh()->getSpaceDimension()!=dim) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::ComputeOffsetFromTwoToOne : dimension must be the same !"); + std::vector< int > ret(dim,0); + + for(int i=0;i_mesh),*f2(p2->_mesh); + const MEDCouplingCartesianAMRPatch *p1h(0),*p2h(0); + for(int j=0;jgetFather()),*f2tmp(f2->getFather()); + int pid1(f1tmp->getPatchIdFromChildMesh(f1)),pid2(f2tmp->getPatchIdFromChildMesh(f2)); + p1h=f1tmp->getPatch(pid1); p2h=f2tmp->getPatch(pid2); + f1=f1tmp; f2=f2tmp; + } + std::vector< std::pair > p2c(p2h->getBLTRRange()); + for(int k=0;kgetBLTRRange()[k].first; + ret[k]*=f1->getFactors()[k]; + } + } + return ret; +} + +/*! + * \param [in,out] partBeforeFact - the part of a image mesh in compact format that will be put in refined reference. + * \param [in] factors - the factors per axis. + */ +void MEDCouplingCartesianAMRPatch::ApplyFactorsOnCompactFrmt(std::vector< std::pair >& partBeforeFact, const std::vector& factors) +{ + std::size_t sz(factors.size()); + if(sz!=partBeforeFact.size()) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::ApplyFactorsOnCompactFrmt : size of input vectors must be the same !"); + for(std::size_t i=0;i >& partBeforeFact, int ghostSize) +{ + if(ghostSize<0) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::ApplyGhostOnCompactFrmt : ghost size must be >= 0 !"); + std::size_t sz(partBeforeFact.size()); + for(std::size_t i=0;i >& partBeforeFact, int ghostSize) +{ + if(ghostSize<0) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRPatch::ApplyAllGhostOnCompactFrmt : ghost size must be >= 0 !"); + std::size_t sz(partBeforeFact.size()); + for(std::size_t i=0;isetData(this); +} + +void MEDCouplingDataForGodFather::checkGodFatherFrozen() const +{ + _tlc.checkConst(); +} + +bool MEDCouplingDataForGodFather::changeGodFather(MEDCouplingCartesianAMRMesh *gf) +{ + bool ret(_tlc.keepTrackOfNewTL(gf)); + if(ret) + { + _gf=gf; + } + return ret; +} + /// @endcond int MEDCouplingCartesianAMRMeshGen::getSpaceDimension() const @@ -156,6 +432,7 @@ void MEDCouplingCartesianAMRMeshGen::setFactors(const std::vector& newFacto if(!_patches.empty()) throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::setFactors : modification of factors is not allowed when presence of patches !"); _factors=newFactors; + declareAsNew(); } int MEDCouplingCartesianAMRMeshGen::getMaxNumberOfLevelsRelativeToThis() const @@ -166,11 +443,33 @@ int MEDCouplingCartesianAMRMeshGen::getMaxNumberOfLevelsRelativeToThis() const return ret; } +/*! + * This method returns the number of cells of \a this with the help of the MEDCouplingIMesh instance representing \a this. + * The patches in \a this are ignored here. + * \sa getNumberOfCellsAtCurrentLevelGhost, getNumberOfCellsRecursiveWithOverlap + */ int MEDCouplingCartesianAMRMeshGen::getNumberOfCellsAtCurrentLevel() const { return _mesh->getNumberOfCells(); } +/*! + * This method returns the number of cells of \a this with the help of the MEDCouplingIMesh instance representing \a this enlarged by \a ghostLev size + * to take into account of the ghost cells for future computation. + * The patches in \a this are ignored here. + * + * \sa getNumberOfCellsAtCurrentLevel + */ +int MEDCouplingCartesianAMRMeshGen::getNumberOfCellsAtCurrentLevelGhost(int ghostLev) const +{ + MEDCouplingAutoRefCountObjectPtr tmp(_mesh->buildWithGhost(ghostLev)); + return tmp->getNumberOfCells(); +} + +/*! + * This method returns the number of cells including the current level but \b also \b including recursively all cells of other levels + * starting from this. The set of cells which size is returned here are generally overlapping each other. + */ int MEDCouplingCartesianAMRMeshGen::getNumberOfCellsRecursiveWithOverlap() const { int ret(_mesh->getNumberOfCells()); @@ -181,6 +480,13 @@ int MEDCouplingCartesianAMRMeshGen::getNumberOfCellsRecursiveWithOverlap() const return ret; } +/*! + * This method returns the max number of cells covering all the space without overlapping. + * It returns the number of cells of the mesh with the highest resolution. + * The returned value is equal to the number of cells of mesh returned by buildUnstructured. + * + * \sa buildUnstructured + */ int MEDCouplingCartesianAMRMeshGen::getNumberOfCellsRecursiveWithoutOverlap() const { int ret(_mesh->getNumberOfCells()); @@ -241,6 +547,7 @@ std::vector MEDCouplingCartesianAMRMeshGen::r void MEDCouplingCartesianAMRMeshGen::detachFromFather() { _father=0; + declareAsNew(); } /*! @@ -256,6 +563,7 @@ void MEDCouplingCartesianAMRMeshGen::addPatch(const std::vector< std::pair zeMesh(new MEDCouplingCartesianAMRMeshSub(this,mesh)); MEDCouplingAutoRefCountObjectPtr elt(new MEDCouplingCartesianAMRPatch(zeMesh,bottomLeftTopRight)); _patches.push_back(elt); + declareAsNew(); } /// @cond INTERNAL @@ -570,6 +878,7 @@ void MEDCouplingCartesianAMRMeshGen::createPatchesFromCriterion(const INTERP_KER } for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=listOfPatchesOK.begin();it!=listOfPatchesOK.end();it++) addPatch((*it)->getConstPart(),factors); + declareAsNew(); } /*! @@ -581,6 +890,7 @@ void MEDCouplingCartesianAMRMeshGen::createPatchesFromCriterion(const INTERP_KER throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMesh::createPatchesFromCriterion : the criterion DataArrayByte instance must be allocated and not NULL !"); std::vector crit(criterion->toVectorOfBool());//check that criterion has one component. createPatchesFromCriterion(bso,crit,factors); + declareAsNew(); } void MEDCouplingCartesianAMRMeshGen::removeAllPatches() @@ -607,6 +917,26 @@ int MEDCouplingCartesianAMRMeshGen::getNumberOfPatches() const return (int)_patches.size(); } +int MEDCouplingCartesianAMRMeshGen::getPatchIdFromChildMesh(const MEDCouplingCartesianAMRMeshGen *mesh) const +{ + int ret(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_patches.begin();it!=_patches.end();it++,ret++) + { + if((*it)->getMesh()==mesh) + return ret; + } + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::getPatchIdFromChildMesh : no such a mesh in my direct progeny !"); +} + +std::vector< const MEDCouplingCartesianAMRPatch *> MEDCouplingCartesianAMRMeshGen::getPatches() const +{ + std::size_t sz(_patches.size()); + std::vector< const MEDCouplingCartesianAMRPatch *> ret(sz); + for(std::size_t i=0;i=0 !"); const MEDCouplingCartesianAMRPatch *p1(getPatch(patchId1)),*p2(getPatch(patchId2)); - if(_factors.empty()) - throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMesh::isPatchInNeighborhoodOf : no factors defined !"); - int ghostLevInPatchRef; - if(ghostLev==0) - ghostLevInPatchRef=0; - else - { - ghostLevInPatchRef=(ghostLev-1)/_factors[0]+1; - for(std::size_t i=0;i<_factors.size();i++) - ghostLevInPatchRef=std::max(ghostLevInPatchRef,(ghostLev-1)/_factors[i]+1); - } - return p1->isInMyNeighborhood(p2,ghostLevInPatchRef); + return p1->isInMyNeighborhood(p2,GetGhostLevelInFineRef(ghostLev,_factors)); } /*! @@ -698,6 +1015,23 @@ void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchGhost(int patchId, cons MEDCouplingIMesh::SpreadCoarseToFineGhost(cellFieldOnThis,_mesh->getCellGridStructure(),cellFieldOnPatch,patch->getBLTRRange(),getFactors(),ghostLev); } +/*! + * This method is equivalent to fillCellFieldOnPatchGhost except that here \b ONLY \b the \b ghost \b zone will be updated + * in \a cellFieldOnPatch. + * + * \param [in] patchId - The id of the patch \a cellFieldOnThis has to be put on. + * \param [in] cellFieldOnThis - The array of the cell field on \c this->getImageMesh() to be projected to patch having id \a patchId. + * \param [in,out] cellFieldOnPatch - The array of the cell field on the requested patch to be filled \b only \b in \b the \b ghost \b zone. + * \param [in] ghostLev - The size of the ghost zone (must be >=0 !) + */ +void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchOnlyOnGhostZone(int patchId, const DataArrayDouble *cellFieldOnThis, DataArrayDouble *cellFieldOnPatch, int ghostLev) const +{ + if(!cellFieldOnThis || !cellFieldOnThis->isAllocated()) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMesh::fillCellFieldOnPatchOnlyOnGhostZone : the input cell field array is NULL or not allocated !"); + const MEDCouplingCartesianAMRPatch *patch(getPatch(patchId)); + MEDCouplingIMesh::SpreadCoarseToFineGhostZone(cellFieldOnThis,_mesh->getCellGridStructure(),cellFieldOnPatch,patch->getBLTRRange(),getFactors(),ghostLev); +} + /*! * This method is a refinement of fillCellFieldOnPatchGhost. fillCellFieldOnPatchGhost is first called. * Then for all other patches than those pointed by \a patchId that overlap the ghost zone of the patch impact the ghost zone adequately. @@ -707,10 +1041,12 @@ void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchGhost(int patchId, cons * \param [in,out] cellFieldOnPatch - The array of the cell field on the requested patch to be filled. * \param [in] ghostLev - The size of the ghost zone (must be >=0 !) * \param [in] arrsOnPatches - \b WARNING arrsOnPatches[patchId] is \b NOT \b const. All others are const. + * + * \sa fillCellFieldOnPatchOnlyGhostAdv */ void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchGhostAdv(int patchId, const DataArrayDouble *cellFieldOnThis, int ghostLev, const std::vector& arrsOnPatches) const { - int nbp(getNumberOfPatches()),dim(getSpaceDimension()); + int nbp(getNumberOfPatches()); if(nbp!=(int)arrsOnPatches.size()) { std::ostringstream oss; oss << "MEDCouplingCartesianAMRMesh::fillCellFieldOnPatchGhostAdv : there are " << nbp << " patches in this and " << arrsOnPatches.size() << " arrays in the last parameter !"; @@ -719,41 +1055,38 @@ void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchGhostAdv(int patchId, c DataArrayDouble *theFieldToFill(const_cast(arrsOnPatches[patchId])); // first, do as usual fillCellFieldOnPatchGhost(patchId,cellFieldOnThis,theFieldToFill,ghostLev); - // all reference patch stuff + fillCellFieldOnPatchOnlyGhostAdv(patchId,ghostLev,arrsOnPatches); +} + +/*! + * This method updates the patch with id \a patchId considering the only the all the patches in \a this to fill ghost zone. + * So \b warning, the DataArrayDouble instance \a arrsOnPatches[patchId] is non const. + * + * \sa getPatchIdsInTheNeighborhoodOf + */ +void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchOnlyGhostAdv(int patchId, int ghostLev, const std::vector& arrsOnPatches) const +{ + int nbp(getNumberOfPatches()); + if(nbp!=(int)arrsOnPatches.size()) + { + std::ostringstream oss; oss << "MEDCouplingCartesianAMRMesh::fillCellFieldOnPatchOnlyGhostAdv : there are " << nbp << " patches in this and " << arrsOnPatches.size() << " arrays in the last parameter !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } const MEDCouplingCartesianAMRPatch *refP(getPatch(patchId)); - const std::vector< std::pair >& refBLTR(refP->getBLTRRange());//[(1,4),(2,4)] - std::vector dimsCoarse(MEDCouplingStructuredMesh::GetDimensionsFromCompactFrmt(refBLTR));//[3,2] - std::transform(dimsCoarse.begin(),dimsCoarse.end(),_factors.begin(),dimsCoarse.begin(),std::multiplies());//[12,8] - std::transform(dimsCoarse.begin(),dimsCoarse.end(),dimsCoarse.begin(),std::bind2nd(std::plus(),2*ghostLev));//[14,10] - std::vector< std::pair > rangeCoarse(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(dimsCoarse));//[(0,14),(0,10)] - std::vector fakeFactors(dim,1); - // - for(int i=0;i(arrsOnPatches[patchId])); + std::vector ids(getPatchIdsInTheNeighborhoodOf(patchId,ghostLev)); + for(std::vector::const_iterator it=ids.begin();it!=ids.end();it++) { - if(i!=patchId) - if(isPatchInNeighborhoodOf(i,patchId,ghostLev)) - { - const MEDCouplingCartesianAMRPatch *otherP(getPatch(i)); - const std::vector< std::pair >& otherBLTR(otherP->getBLTRRange());//[(4,5),(3,4)] - std::vector< std::pair > tmp0,tmp1,tmp2; - MEDCouplingStructuredMesh::ChangeReferenceFromGlobalOfCompactFrmt(refBLTR,otherBLTR,tmp0,false);//tmp0=[(3,4),(1,2)] - ApplyFactorsOnCompactFrmt(tmp0,_factors);//tmp0=[(12,16),(4,8)] - ApplyGhostOnCompactFrmt(tmp0,ghostLev);//tmp0=[(13,17),(5,9)] - std::vector< std::pair > interstRange(MEDCouplingStructuredMesh::IntersectRanges(tmp0,rangeCoarse));//interstRange=[(13,14),(5,9)] - MEDCouplingStructuredMesh::ChangeReferenceFromGlobalOfCompactFrmt(otherBLTR,refBLTR,tmp1,false);//tmp1=[(-3,0),(-1,1)] - ApplyFactorsOnCompactFrmt(tmp1,_factors);//tmp1=[(-12,-4),(-4,0)] - MEDCouplingStructuredMesh::ChangeReferenceToGlobalOfCompactFrmt(tmp1,interstRange,tmp2,false);//tmp2=[(1,2),(1,5)] - // - std::vector< std::pair > dimsFine(otherBLTR); - ApplyFactorsOnCompactFrmt(dimsFine,_factors); - ApplyAllGhostOnCompactFrmt(dimsFine,ghostLev); - // - MEDCouplingAutoRefCountObjectPtr ghostVals(MEDCouplingStructuredMesh::ExtractFieldOfDoubleFrom(MEDCouplingStructuredMesh::GetDimensionsFromCompactFrmt(dimsFine),arrsOnPatches[i],tmp2)); - MEDCouplingIMesh::CondenseFineToCoarse(dimsCoarse,ghostVals,interstRange,fakeFactors,theFieldToFill); - } + const MEDCouplingCartesianAMRPatch *otherP(getPatch(*it)); + MEDCouplingCartesianAMRPatch::UpdateNeighborsOfOneWithTwo(ghostLev,_factors,refP,otherP,theFieldToFill,arrsOnPatches[*it]); } } +void MEDCouplingCartesianAMRMeshGen::fillCellFieldOnPatchOnlyOnGhostZoneWith(int ghostLev, const MEDCouplingCartesianAMRPatch *patchToBeModified, const MEDCouplingCartesianAMRPatch *neighborPatch, DataArrayDouble *cellFieldOnPatch, const DataArrayDouble *cellFieldNeighbor) const +{ + MEDCouplingCartesianAMRPatch::UpdateNeighborsOfOneWithTwo(ghostLev,_factors,patchToBeModified,neighborPatch,cellFieldOnPatch,cellFieldNeighbor); +} + /*! * This method updates \a cellFieldOnThis part of values coming from the cell field \a cellFieldOnPatch lying on patch having id \a patchId. * @@ -874,6 +1207,78 @@ MEDCoupling1SGTUMesh *MEDCouplingCartesianAMRMeshGen::buildMeshOfDirectChildrenO return MEDCoupling1SGTUMesh::Merge1SGTUMeshes(patches); } +/*! + * This method works same as buildUnstructured except that arrays are given in input to build a field on cell in output. + * \return MEDCouplingFieldDouble * - a newly created instance the caller has reponsability to deal with. + * \sa buildUnstructured + */ +MEDCouplingFieldDouble *MEDCouplingCartesianAMRMeshGen::buildCellFieldOnRecurseWithoutOverlapWithoutGhost(int ghostSz, const std::vector& recurseArrs) const +{ + if(recurseArrs.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::buildCellFieldOnRecurseWithoutOverlapWithoutGhost : array is empty ! Should never happen !"); + // + std::vector bs(_mesh->getNumberOfCells(),false); + std::vector cgs(_mesh->getCellGridStructure()); + std::vector< MEDCouplingAutoRefCountObjectPtr > msSafe(_patches.size()+1); + std::size_t ii(0); + for(std::vector< MEDCouplingAutoRefCountObjectPtr >::const_iterator it=_patches.begin();it!=_patches.end();it++,ii++) + { + MEDCouplingStructuredMesh::SwitchOnIdsFrom(cgs,(*it)->getBLTRRange(),bs); + std::vector tmpArrs(extractSubTreeFromGlobalFlatten((*it)->getMesh(),recurseArrs)); + msSafe[ii+1]=(*it)->getMesh()->buildCellFieldOnRecurseWithoutOverlapWithoutGhost(ghostSz,tmpArrs); + } + MEDCouplingAutoRefCountObjectPtr eltsOff(DataArrayInt::BuildListOfSwitchedOff(bs)); + // + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingFieldDouble::New(ON_CELLS)); + MEDCouplingAutoRefCountObjectPtr arr2(extractGhostFrom(ghostSz,recurseArrs[0])); + arr2=arr2->selectByTupleIdSafe(eltsOff->begin(),eltsOff->end()); + ret->setArray(arr2); + ret->setName(arr2->getName()); + MEDCouplingAutoRefCountObjectPtr part(_mesh->buildUnstructured()); + MEDCouplingAutoRefCountObjectPtr mesh(part->buildPartOfMySelf(eltsOff->begin(),eltsOff->end(),false)); + ret->setMesh(mesh); + msSafe[0]=ret; + // + std::vector< const MEDCouplingFieldDouble * > ms(msSafe.size()); + for(std::size_t i=0;ibuildWithGhost(ghostSz). + */ +DataArrayDouble *MEDCouplingCartesianAMRMeshGen::extractGhostFrom(int ghostSz, const DataArrayDouble *arr) const +{ + std::vector st(_mesh->getCellGridStructure()); + std::vector< std::pair > p(MEDCouplingStructuredMesh::GetCompactFrmtFromDimensions(st)); + std::transform(st.begin(),st.end(),st.begin(),std::bind2nd(std::plus(),2*ghostSz)); + MEDCouplingCartesianAMRPatch::ApplyGhostOnCompactFrmt(p,ghostSz); + MEDCouplingAutoRefCountObjectPtr ret(MEDCouplingStructuredMesh::ExtractFieldOfDoubleFrom(st,arr,p)); + return ret.retn(); +} + +/*! + * This method returns all the patches in \a this not equal to \a patchId that are in neighborhood of patch with id \a patchId. + * + * \sa fillCellFieldOnPatchOnlyGhostAdv + */ +std::vector MEDCouplingCartesianAMRMeshGen::getPatchIdsInTheNeighborhoodOf(int patchId, int ghostLev) const +{ + std::vector ret; + int nbp(getNumberOfPatches()); + // + for(int i=0;i >& partBeforeFact, const std::vector& factors) +int MEDCouplingCartesianAMRMeshGen::GetGhostLevelInFineRef(int ghostLev, const std::vector& factors) { - std::size_t sz(factors.size()); - if(sz!=partBeforeFact.size()) - throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::ApplyFactorsOnCompactFrmt : size of input vectors must be the same !"); - for(std::size_t i=0;i >& partBeforeFact, int ghostSize) -{ - if(ghostSize<0) - throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::ApplyGhostOnCompactFrmt : ghost size must be >= 0 !"); - std::size_t sz(partBeforeFact.size()); - for(std::size_t i=0;i=0 !"); + if(factors.empty()) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMesh::GetGhostLevelInFineRef : no factors defined !"); + int ghostLevInPatchRef; + if(ghostLev==0) + ghostLevInPatchRef=0; + else { - partBeforeFact[i].first+=ghostSize; - partBeforeFact[i].second+=ghostSize; + ghostLevInPatchRef=(ghostLev-1)/factors[0]+1; + for(std::size_t i=0;i >& partBeforeFact, int ghostSize) +std::vector MEDCouplingCartesianAMRMeshGen::extractSubTreeFromGlobalFlatten(const MEDCouplingCartesianAMRMeshGen *head, const std::vector& all) const { - if(ghostSize<0) - throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::ApplyAllGhostOnCompactFrmt : ghost size must be >= 0 !"); - std::size_t sz(partBeforeFact.size()); - for(std::size_t i=0;i ret; + std::vector meshes(1,this); + std::size_t kk(0); + for(int i=0;i meshesTmp; + for(std::vector::const_iterator it=meshes.begin();it!=meshes.end();it++) + { + if((*it)==head || head->isObjectInTheProgeny(*it)) + ret.push_back(all[kk]); + kk++; + std::vector< const MEDCouplingCartesianAMRPatch *> ps((*it)->getPatches()); + for(std::vector< const MEDCouplingCartesianAMRPatch *>::const_iterator it0=ps.begin();it0!=ps.end();it0++) + { + const MEDCouplingCartesianAMRMeshGen *mesh((*it0)->getMesh()); + meshesTmp.push_back(mesh); + } + } + meshes=meshesTmp; } + if(kk!=all.size()) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMeshGen::extractSubTreeFromGlobalFlatten : the size of input vector is not compatible with number of leaves in this !"); + return ret; } std::size_t MEDCouplingCartesianAMRMeshGen::getHeapMemorySizeWithoutChildren() const @@ -1039,7 +1444,54 @@ MEDCouplingCartesianAMRMesh *MEDCouplingCartesianAMRMesh::New(const std::string& return new MEDCouplingCartesianAMRMesh(meshName,spaceDim,nodeStrctStart,nodeStrctStop,originStart,originStop,dxyzStart,dxyzStop); } +void MEDCouplingCartesianAMRMesh::setData(MEDCouplingDataForGodFather *data) +{ + MEDCouplingDataForGodFather *myData(_data); + if(myData==data) + return ; + if(myData) + myData->changeGodFather(0); + _data=data; + if(data) + data->incrRef(); +} + +void MEDCouplingCartesianAMRMesh::allocData() const +{ + checkData(); + _data->alloc(); +} + +void MEDCouplingCartesianAMRMesh::deallocData() const +{ + checkData(); + _data->dealloc(); +} + MEDCouplingCartesianAMRMesh::MEDCouplingCartesianAMRMesh(const std::string& meshName, int spaceDim, const int *nodeStrctStart, const int *nodeStrctStop, const double *originStart, const double *originStop, const double *dxyzStart, const double *dxyzStop):MEDCouplingCartesianAMRMeshGen(meshName,spaceDim,nodeStrctStart,nodeStrctStop,originStart,originStop,dxyzStart,dxyzStop) { } + +std::vector MEDCouplingCartesianAMRMesh::getDirectChildren() const +{ + std::vector ret(MEDCouplingCartesianAMRMeshGen::getDirectChildren()); + const MEDCouplingDataForGodFather *pt(_data); + if(pt) + ret.push_back(pt); + return ret; +} + +void MEDCouplingCartesianAMRMesh::checkData() const +{ + const MEDCouplingDataForGodFather *data(_data); + if(!data) + throw INTERP_KERNEL::Exception("MEDCouplingCartesianAMRMesh::checkData : no data set !"); +} + +MEDCouplingCartesianAMRMesh::~MEDCouplingCartesianAMRMesh() +{ + MEDCouplingDataForGodFather *data(_data); + if(data) + data->changeGodFather(0); +}