+/*!
+ * Computes the symmetry of \a this.
+ * \return a new object.
+ */
+MCAuto<MEDFileUMesh> MEDFileUMesh::symmetry3DPlane(const double point[3], const double normalVector[3]) const
+{
+ MCAuto<MEDFileUMesh> ret(deepCopy());
+ DataArrayDouble *myCoo(getCoords());
+ if(myCoo)
+ {
+ MCAuto<DataArrayDouble> newCoo(myCoo->symmetry3DPlane(point,normalVector));
+ ret->setCoordsForced(newCoo);
+ }
+ return ret;
+}
+
+/*!
+ * Aggregate the given MEDFileUMesh objects into a single mesh. When groups are present, those are
+ * merged in such a way that the final mesh contain all of them.
+ * \return a new object.
+ */
+MCAuto<MEDFileUMesh> MEDFileUMesh::Aggregate(const std::vector<const MEDFileUMesh *>& meshes)
+{
+ if(meshes.empty())
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : empty input vector !");
+ std::size_t sz(meshes.size()),i(0);
+ std::vector<const DataArrayDouble *> coos(sz);
+ std::vector<const DataArrayInt *> fam_coos(sz),num_coos(sz);
+ for(auto it=meshes.begin();it!=meshes.end();it++,i++)
+ {
+ if(!(*it))
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : presence of NULL pointer in input vector !");
+ coos[i]=(*it)->getCoords();
+ fam_coos[i]=(*it)->getFamilyFieldAtLevel(1);
+ num_coos[i]=(*it)->getNumberFieldAtLevel(1);
+ }
+ const MEDFileUMesh *ref(meshes[0]);
+ int spaceDim(ref->getSpaceDimension()),meshDim(ref->getMeshDimension());
+ std::vector<int> levs(ref->getNonEmptyLevels());
+ std::map<int, std::vector<const DataArrayInt *> > m_fam,m_renum;
+ std::map<int, std::vector< MCAuto< MEDCouplingUMesh > > > m_mesh2;
+ std::map<int, std::vector<const MEDCouplingUMesh *> > m_mesh;
+ std::map<std::string,int> famNumMap;
+ std::map<int, std::string> famNumMap_rev;
+ std::map<std::string, std::vector<std::string> > grpFamMap;
+ std::set< MCAuto<DataArrayInt> > mem_cleanup; // Memory clean-up. At set deletion (end of method), arrays will be deallocated.
+
+ // Identify min family number used:
+ int min_fam_num(0);
+ for(const auto& msh : meshes)
+ {
+ const std::map<std::string,int>& locMap1(msh->getFamilyInfo());
+ for(const auto& it3 : locMap1)
+ if(it3.second < min_fam_num)
+ min_fam_num = it3.second;
+ }
+
+ for(const auto& msh : meshes)
+ {
+ if(msh->getSpaceDimension()!=spaceDim)
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : space dimension must be homogeneous !");
+ if(msh->getMeshDimension()!=meshDim)
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : mesh dimension must be homogeneous !");
+ if(msh->getNonEmptyLevels()!=levs)
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : levels must be the same for elements in input vector !");
+
+ const std::map<std::string,int>& locMap1(msh->getFamilyInfo());
+ std::map<std::string, std::string> substitute;
+ std::map<int, int> substituteN;
+ bool fam_conflict(false);
+ for(const auto& it3 : locMap1)
+ {
+ const std::string& famName = it3.first;
+ int famNum = it3.second;
+ if (famNumMap_rev.find(famNum) != famNumMap_rev.end()) // Family number is already used!
+ {
+ // Is it used by a group of the current mesh or a group from a previous mesh?
+ // If not, this is OK (typically -1 familly).
+ bool used = false;
+ // Current mesh
+ const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
+ for(const auto& it4 : locMap2)
+ {
+ const auto& famLst = it4.second;
+ if (std::find(famLst.begin(), famLst.end(), famName) != famLst.end())
+ { used = true; break; }
+ }
+ // Previous meshes ...
+ if (!used)
+ for(const auto& it4 : grpFamMap)
+ {
+ const auto& famLst = it4.second;
+ if (std::find(famLst.begin(), famLst.end(), famName) != famLst.end())
+ { used = true; break; }
+ }
+
+ if(used)
+ { // Generate a new family name, and a new family number
+ fam_conflict = true;
+ std::ostringstream oss;
+ oss << "Family_" << --min_fam_num; // New ID
+ std::string new_name(oss.str());
+ substitute[famName] = new_name;
+ substituteN[famNum] = min_fam_num;
+ famNumMap[new_name] = min_fam_num;
+ famNumMap_rev[min_fam_num] = new_name;
+ }
+ }
+ famNumMap[famName] = famNum;
+ famNumMap_rev[famNum] = famName;
+ }
+
+ for(const auto& level : levs)
+ {
+ MCAuto<MEDCouplingUMesh> locMesh(msh->getMeshAtLevel(level));
+ m_mesh[level].push_back(locMesh); m_mesh2[level].push_back(locMesh);
+ m_renum[level].push_back(msh->getNumberFieldAtLevel(level));
+
+ // Family field - substitute new family number if needed:
+ if(fam_conflict)
+ {
+ DataArrayInt* dai(msh->getFamilyFieldAtLevel(level)->deepCopy()); // Need a copy
+ mem_cleanup.insert(MCAuto<DataArrayInt>(dai)); // Make sure array will decrRef() at end of method
+ for (const auto& subN : substituteN)
+ dai->changeValue(subN.first, subN.second);
+ m_fam[level].push_back(dai);
+ }
+ else
+ m_fam[level].push_back(msh->getFamilyFieldAtLevel(level)); // No copy needed
+ }
+
+ const std::map<std::string, std::vector<std::string> >& locMap2(msh->getGroupInfo());
+ for(const auto& grpItem : locMap2)
+ {
+ const std::string& grpName = grpItem.first;
+ std::vector<std::string> famLst;
+ // Substitute family name in group description if needed:
+ if (fam_conflict)
+ {
+ famLst = grpItem.second;
+ for (const auto& sub : substitute)
+ std::replace(famLst.begin(), famLst.end(), sub.first, sub.second);
+ }
+ else
+ famLst = grpItem.second;
+
+ // Potentially merge groups (if same name):
+ const auto& it = grpFamMap.find(grpName);
+ if (it != grpFamMap.end())
+ {
+ // Group already exists, merge should be done. Normally we whould never
+ // have twice the same family name in famLstCur and famLst since we dealt with family number
+ // conflict just above ...
+ std::vector<std::string>& famLstCur = (*it).second;
+ famLstCur.insert(famLstCur.end(), famLst.begin(), famLst.end());
+ }
+ else
+ grpFamMap[grpName] = famLst;
+ }
+ }
+ // Easy part : nodes
+ MCAuto<MEDFileUMesh> ret(MEDFileUMesh::New());
+ MCAuto<DataArrayDouble> coo(DataArrayDouble::Aggregate(coos));
+ ret->setCoords(coo);
+ if(std::find(fam_coos.begin(),fam_coos.end(),(const DataArrayInt *)0)==fam_coos.end())
+ {
+ MCAuto<DataArrayInt> fam_coo(DataArrayInt::Aggregate(fam_coos));
+ ret->setFamilyFieldArr(1,fam_coo);
+ }
+ if(std::find(num_coos.begin(),num_coos.end(),(const DataArrayInt *)0)==num_coos.end())
+ {
+ MCAuto<DataArrayInt> num_coo(DataArrayInt::Aggregate(num_coos));
+ ret->setRenumFieldArr(1,num_coo);
+ }
+ // cells
+ for(const auto& level : levs)
+ {
+ auto it2(m_mesh.find(level));
+ if(it2==m_mesh.end())
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 1 !");
+ MCAuto<MEDCouplingUMesh> mesh(MEDCouplingUMesh::MergeUMeshes((*it2).second));
+ mesh->setCoords(coo); mesh->setName(ref->getName());
+ MCAuto<DataArrayInt> renum(mesh->sortCellsInMEDFileFrmt());
+ ret->setMeshAtLevel(level,mesh);
+ auto it3(m_fam.find(level)),it4(m_renum.find(level));
+ if(it3==m_fam.end()) // Should never happen (all levels exist for all meshes)
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 2!");
+ if(it4==m_renum.end())
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::Aggregate : internal error 3!");
+ // Set new family field if it was defined for all input meshes
+ const std::vector<const DataArrayInt *>& fams((*it3).second);
+ if(std::find(fams.begin(),fams.end(),(const DataArrayInt *)0)==fams.end())
+ {
+ MCAuto<DataArrayInt> famm(DataArrayInt::Aggregate(fams));
+ famm->renumberInPlace(renum->begin());
+ ret->setFamilyFieldArr(level,famm);
+ }
+ // Set optional number field if defined for all input meshes:
+ const std::vector<const DataArrayInt *>& renums((*it4).second);
+ if(std::find(renums.begin(),renums.end(),(const DataArrayInt *)0)==renums.end())
+ {
+ MCAuto<DataArrayInt> renumm(DataArrayInt::Aggregate(renums));
+ renumm->renumberInPlace(renum->begin());
+ ret->setRenumFieldArr(level,renumm);
+ }
+ }
+ //
+ ret->setFamilyInfo(famNumMap);
+ ret->setGroupInfo(grpFamMap);
+ ret->setName(ref->getName());
+ return ret;
+}
+
+MEDCouplingMappedExtrudedMesh *MEDFileUMesh::convertToExtrudedMesh() const
+{
+ if(getMeshDimension()!=3)
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::convertToExtrudedMesh : works only for 3D mesh !");
+ MCAuto<MEDCouplingUMesh> m3D(getMeshAtLevel(0)),m2D(getMeshAtLevel(-1));
+ if(m3D.isNull() || m2D.isNull())
+ throw INTERP_KERNEL::Exception("MEDFileUMesh::convertToExtrudedMesh : this must be defined both at level 0 and level -1 !");
+ int zeId(std::numeric_limits<int>::max()-getFamilyId(GetSpeStr4ExtMesh()));
+ MCAuto<MEDCouplingMappedExtrudedMesh> ret(MEDCouplingMappedExtrudedMesh::New(m3D,m2D,zeId));
+ return ret.retn();
+}
+