Salome HOME
5572831aca0cd95fc3386b3de51f042e1734178e
[tools/medcoupling.git] / src / MEDCoupling / MEDCouplingGaussLocalization.cxx
1 // Copyright (C) 2007-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "MEDCouplingGaussLocalization.hxx"
22 #include "InterpKernelGaussCoords.hxx"
23 #include "MEDCoupling1GTUMesh.hxx"
24 #include "MEDCouplingUMesh.hxx"
25 #include "CellModel.hxx"
26
27 #include <cmath>
28 #include <numeric>
29 #include <sstream>
30 #include <iterator>
31 #include <algorithm>
32
33 using namespace MEDCoupling;
34
35 MEDCouplingGaussLocalization::MEDCouplingGaussLocalization(INTERP_KERNEL::NormalizedCellType type, const std::vector<double>& refCoo,
36                                                            const std::vector<double>& gsCoo, const std::vector<double>& w)
37 try:_type(type),_ref_coord(refCoo),_gauss_coord(gsCoo),_weight(w)
38 {
39   checkConsistencyLight();
40 }
41 catch(INTERP_KERNEL::Exception& e)
42 {
43     _type=INTERP_KERNEL::NORM_ERROR;
44     _ref_coord.clear();
45     _gauss_coord.clear();
46     _weight.clear();
47     throw e;
48 }
49
50 MEDCouplingGaussLocalization::MEDCouplingGaussLocalization(INTERP_KERNEL::NormalizedCellType typ)
51 try:_type(typ)
52 {
53   INTERP_KERNEL::CellModel::GetCellModel(_type);
54 }
55 catch(INTERP_KERNEL::Exception& e)
56 {
57     _type=INTERP_KERNEL::NORM_ERROR;
58     throw e;
59 }
60
61 void MEDCouplingGaussLocalization::setType(INTERP_KERNEL::NormalizedCellType typ)
62 {
63   INTERP_KERNEL::CellModel::GetCellModel(typ);//throws if not found. This is a check
64   _type=typ;
65 }
66
67 void MEDCouplingGaussLocalization::checkConsistencyLight() const
68 {
69   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(_type);
70   int nbNodes=cm.getNumberOfNodes();
71   int dim=cm.getDimension();
72   if(!cm.isDynamic())
73     {
74       if(ToIdType(_ref_coord.size())!=nbNodes*dim)
75         {
76           std::ostringstream oss; oss << "Invalid size of refCoo : expecting to be : " << nbNodes << " (nbNodePerCell) * " << dim << " (dim) !";
77           throw INTERP_KERNEL::Exception(oss.str().c_str());
78         }
79     }
80   if(_gauss_coord.size()!=dim*_weight.size())
81     {
82       std::ostringstream oss; oss << "Invalid gsCoo size and weight size : gsCoo.size() must be equal to _weight.size() * " << dim << " (dim) !";
83       throw INTERP_KERNEL::Exception(oss.str().c_str());
84     }
85 }
86
87 int MEDCouplingGaussLocalization::getDimension() const
88 {
89   if(_weight.empty())
90     return -1;
91   return (int)_gauss_coord.size()/(int)_weight.size();
92 }
93
94 int MEDCouplingGaussLocalization::getNumberOfPtsInRefCell() const
95 {
96   int dim=getDimension();
97   if(dim==0)
98     return -1;
99   return (int)_ref_coord.size()/dim;
100 }
101
102 std::string MEDCouplingGaussLocalization::getStringRepr() const
103 {
104   std::ostringstream oss;
105   oss << "CellType : " << INTERP_KERNEL::CellModel::GetCellModel(_type).getRepr() << std::endl;
106   oss << "Ref coords : "; std::copy(_ref_coord.begin(),_ref_coord.end(),std::ostream_iterator<double>(oss,", ")); oss << std::endl;
107   oss << "Localization coords : "; std::copy(_gauss_coord.begin(),_gauss_coord.end(),std::ostream_iterator<double>(oss,", ")); oss << std::endl;
108   oss << "Weight : "; std::copy(_weight.begin(),_weight.end(),std::ostream_iterator<double>(oss,", ")); oss << std::endl;
109   return oss.str();
110 }
111
112 std::size_t MEDCouplingGaussLocalization::getMemorySize() const
113 {
114   std::size_t ret=0;
115   ret+=_ref_coord.capacity()*sizeof(double);
116   ret+=_gauss_coord.capacity()*sizeof(double);
117   ret+=_weight.capacity()*sizeof(double);
118   return ret;
119 }
120
121 bool MEDCouplingGaussLocalization::isEqual(const MEDCouplingGaussLocalization& other, double eps) const
122 {
123   if(_type!=other._type)
124     return false;
125   if(!AreAlmostEqual(_ref_coord,other._ref_coord,eps))
126     return false;
127   if(!AreAlmostEqual(_gauss_coord,other._gauss_coord,eps))
128     return false;
129   if(!AreAlmostEqual(_weight,other._weight,eps))
130     return false;
131   return true;
132 }
133
134 double MEDCouplingGaussLocalization::getRefCoord(int ptIdInCell, int comp) const
135 {
136   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(_type);
137   int nbNodes=cm.getNumberOfNodes();
138   int dim=cm.getDimension();
139   if(ptIdInCell<0 || ptIdInCell>=nbNodes)
140     throw INTERP_KERNEL::Exception("ptIdInCell specified is invalid : must be in [0;nbNodesPerCell) !");
141   if(comp<0 || comp>=dim)
142     throw INTERP_KERNEL::Exception("comp specified is invalid : must be in [0:dimOfCell) !");
143   return _ref_coord[ptIdInCell*dim+comp];
144 }
145
146 double MEDCouplingGaussLocalization::getGaussCoord(int gaussPtIdInCell, int comp) const
147 {
148   int dim=checkCoherencyOfRequest(gaussPtIdInCell,comp);
149   return _gauss_coord[gaussPtIdInCell*dim+comp];
150 }
151
152 double MEDCouplingGaussLocalization::getWeight(int gaussPtIdInCell, double newVal) const
153 {
154   checkCoherencyOfRequest(gaussPtIdInCell,0);
155   return _weight[gaussPtIdInCell];
156 }
157
158 /*!
159  * Completely useless method for end user. Only for CORBA MPI serialization/unserialization.
160  * push at the end of tinyInfo its basic serialization info. The size of pushed data is always the same.
161  * @param tinyInfo inout parameter.
162  */
163 void MEDCouplingGaussLocalization::pushTinySerializationIntInfo(std::vector<mcIdType>& tinyInfo) const
164 {
165   tinyInfo.push_back(ToIdType(_type));
166   tinyInfo.push_back(getNumberOfPtsInRefCell());
167   tinyInfo.push_back(getNumberOfGaussPt());
168 }
169
170 /*!
171  * Completely useless method for end user. Only for CORBA MPI serialization/unserialization.
172  * push at the end of tinyInfo its basic serialization info. The size of pushed data is \b NOT always the same contrary to pushTinySerializationIntInfo.
173  * @param tinyInfo inout parameter.
174  */
175 void MEDCouplingGaussLocalization::pushTinySerializationDblInfo(std::vector<double>& tinyInfo) const
176 {
177   tinyInfo.insert(tinyInfo.end(),_ref_coord.begin(),_ref_coord.end());
178   tinyInfo.insert(tinyInfo.end(),_gauss_coord.begin(),_gauss_coord.end());
179   tinyInfo.insert(tinyInfo.end(),_weight.begin(),_weight.end());
180 }
181
182 /*!
183  * This method operates the exact inverse operation than MEDCouplingGaussLocalization::pushTinySerializationDblInfo method. This is one of the last step of unserialization process.
184  * This method should be called on an object resized by buildNewInstanceFromTinyInfo static method.
185  * This method takes in argument a pointer 'vals' that point to the begin of double data pushed remotely by pushTinySerializationDblInfo method.
186  * This method returns the pointer 'vals' with an offset of size what it has been read in this method.
187  */
188 const double *MEDCouplingGaussLocalization::fillWithValues(const double *vals)
189 {
190   const double *work=vals;
191   std::copy(work,work+_ref_coord.size(),_ref_coord.begin());
192   work+=_ref_coord.size();
193   std::copy(work,work+_gauss_coord.size(),_gauss_coord.begin());
194   work+=_gauss_coord.size();
195   std::copy(work,work+_weight.size(),_weight.begin());
196   work+=_weight.size();
197   return work;
198 }
199
200 /*!
201  * Given points in \a ptsInRefCoo in the reference coordinates of \a this (in _ref_coord attribute)
202  * this method computes their coordinates in real world for each cells in \a mesh.
203  * So the returned array will contain nbCells* \a ptsInRefCoo->getNumberOfTuples() tuples and the number of component
204  * will be equal to the dimension of \a this.
205  * 
206  * This method ignores Gauss points in \a this and only those in \a ptsInRefCoo are considered here.
207  */
208 MCAuto<DataArrayDouble> MEDCouplingGaussLocalization::localizePtsInRefCooForEachCell(const DataArrayDouble *ptsInRefCoo, const MEDCouplingUMesh *mesh) const
209 {
210   if(!ptsInRefCoo || !mesh)
211     throw INTERP_KERNEL::Exception("MEDCouplingGaussLocalization::localizePtsInRefCooForEachCell : null pointer !");
212   ptsInRefCoo->checkAllocated();
213   mesh->checkConsistencyLight();
214   //
215   mcIdType nbCells=mesh->getNumberOfCells();
216   const double *coords(mesh->getCoords()->begin());
217   const mcIdType *connI(mesh->getNodalConnectivityIndex()->begin()),*conn(mesh->getNodalConnectivity()->begin());
218   //
219   mcIdType nbPts(ptsInRefCoo->getNumberOfTuples());
220   INTERP_KERNEL::NormalizedCellType typ(getType());
221   int dim(INTERP_KERNEL::CellModel::GetCellModel(typ).getDimension()),outDim(mesh->getSpaceDimension());
222   MCAuto<DataArrayDouble> ret(DataArrayDouble::New());
223   ret->alloc(nbPts*nbCells,outDim);
224   double *retPtr(ret->getPointer());
225   if(dim!=ToIdType(ptsInRefCoo->getNumberOfComponents()))
226     throw INTERP_KERNEL::Exception("MEDCouplingGaussLocalization::localizePtsInRefCooForEachCell : number of components of input coo is not equal to dim of element !");
227   const std::vector<double>& wg(getWeights());
228   INTERP_KERNEL::GaussCoords calculator;
229   calculator.addGaussInfo(typ,dim, ptsInRefCoo->begin(),nbPts,&_ref_coord[0],getNumberOfPtsInRefCell());
230   //
231   for(mcIdType i=0;i<nbCells;i++,retPtr+=nbPts*outDim)
232     calculator.calculateCoords(getType(),coords,outDim,conn+connI[i]+1,retPtr);
233   return ret;
234 }
235
236 /*!
237  * This method returns an unstructured mesh that represents the reference cell.
238  */
239 MCAuto<MEDCouplingUMesh> MEDCouplingGaussLocalization::buildRefCell() const
240 {
241   MCAuto<DataArrayDouble> coo(DataArrayDouble::New());
242   const INTERP_KERNEL::CellModel& cm(INTERP_KERNEL::CellModel::GetCellModel(getType()));
243   if(getDimension()!=ToIdType(cm.getDimension()))
244     throw INTERP_KERNEL::Exception("BuildRefCell : dimension mistmatch !");
245   coo->alloc(cm.getNumberOfNodes(),getDimension());
246   std::copy(_ref_coord.begin(),_ref_coord.end(),coo->getPointer());
247   MCAuto<MEDCoupling1SGTUMesh> ret(MEDCoupling1SGTUMesh::New("",getType()));
248   ret->setCoords(coo);
249   MCAuto<DataArrayIdType> conn(DataArrayIdType::New());
250   conn->alloc(cm.getNumberOfNodes(),1);
251   conn->iota();
252   ret->setNodalConnectivity(conn);
253   return MCAuto<MEDCouplingUMesh>(ret->buildUnstructured());
254 }
255
256 /*!
257  * This method sets the comp_th component of ptIdInCell_th point coordinate of reference element of type this->_type.
258  * @throw if not 0<=ptIdInCell<nbOfNodePerCell or if not 0<=comp<dim
259  */
260 void MEDCouplingGaussLocalization::setRefCoord(int ptIdInCell, int comp, double newVal)
261 {
262   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(_type);
263   int nbNodes=cm.getNumberOfNodes();
264   int dim=cm.getDimension();
265   if(ptIdInCell<0 || ptIdInCell>=nbNodes)
266     throw INTERP_KERNEL::Exception("ptIdInCell specified is invalid : must be in [0;nbNodesPerCell) !");
267   if(comp<0 || comp>=dim)
268     throw INTERP_KERNEL::Exception("comp specified is invalid : must be in [0:dimOfCell) !");
269   _ref_coord[ptIdInCell*dim+comp]=newVal;
270 }
271
272 void MEDCouplingGaussLocalization::setGaussCoord(int gaussPtIdInCell, int comp, double newVal)
273 {
274   int dim=checkCoherencyOfRequest(gaussPtIdInCell,comp);
275   _gauss_coord[gaussPtIdInCell*dim+comp]=newVal;
276 }
277
278 void MEDCouplingGaussLocalization::setWeight(int gaussPtIdInCell, double newVal)
279 {
280   checkCoherencyOfRequest(gaussPtIdInCell,0);
281   _weight[gaussPtIdInCell]=newVal;
282 }
283
284 void MEDCouplingGaussLocalization::setRefCoords(const std::vector<double>& refCoo)
285 {
286   _ref_coord=refCoo;
287 }
288
289 void MEDCouplingGaussLocalization::setGaussCoords(const std::vector<double>& gsCoo)
290 {
291   _gauss_coord=gsCoo;
292 }
293
294 void MEDCouplingGaussLocalization::setWeights(const std::vector<double>& w)
295 {
296   _weight=w;
297 }
298
299 /*!
300  * The format of 'tinyData' parameter is the same than pushed in method MEDCouplingGaussLocalization::pushTinySerializationIntInfo.
301  */
302 MEDCouplingGaussLocalization MEDCouplingGaussLocalization::BuildNewInstanceFromTinyInfo(mcIdType dim, const std::vector<mcIdType>& tinyData)
303 {
304   std::vector<double> v1(dim*tinyData[1]),v2(dim*tinyData[2]),v3(tinyData[2]);
305   return MEDCouplingGaussLocalization((INTERP_KERNEL::NormalizedCellType)tinyData[0],v1,v2,v3);
306 }
307
308 int MEDCouplingGaussLocalization::checkCoherencyOfRequest(mcIdType gaussPtIdInCell, int comp) const
309 {
310   const INTERP_KERNEL::CellModel& cm=INTERP_KERNEL::CellModel::GetCellModel(_type);
311   int dim=cm.getDimension();
312   mcIdType nbGsPts=getNumberOfGaussPt();
313   if(gaussPtIdInCell<0 || gaussPtIdInCell>=nbGsPts)
314     throw INTERP_KERNEL::Exception("gaussPtIdInCell specified is invalid : must be in [0:nbGsPts) !");
315   if(comp<0 || comp>=dim)
316     throw INTERP_KERNEL::Exception("comp specified is invalid : must be in [0:dimOfCell) !");
317   return dim;
318 }
319
320 bool MEDCouplingGaussLocalization::AreAlmostEqual(const std::vector<double>& v1, const std::vector<double>& v2, double eps)
321 {
322   std::size_t sz=v1.size();
323   if(sz!=v2.size())
324     return false;
325   std::vector<double> tmp(sz);
326   std::transform(v1.begin(),v1.end(),v2.begin(),tmp.begin(),std::minus<double>());
327   std::transform(tmp.begin(),tmp.end(),tmp.begin(),std::ptr_fun<double,double>(fabs));
328   return *std::max_element(tmp.begin(),tmp.end())<eps;
329 }