1 // Copyright (C) 2007-2013 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "MEDMEM_Remapper.hxx"
21 #include "MEDMEM_Exception.hxx"
22 #include "Interpolation.hxx"
23 #include "Interpolation2D.txx"
24 #include "Interpolation3D.txx"
25 #include "Interpolation3DSurf.hxx"
29 // int InterpolationOptions::_printLevel=0;
30 // IntersectionType InterpolationOptions::_intersectionType=Triangulation;
31 // double InterpolationOptions::_precision=1e-12;;
32 // double InterpolationOptions::_medianPlane =0.5;
33 // bool InterpolationOptions::_doRotate =true;
34 // double InterpolationOptions::_boundingBoxAdjustment =0.1;
35 // int InterpolationOptions::_orientation =0;
36 // SplittingPolicy InterpolationOptions::_splittingPolicy =GENERAL_48;
39 \defgroup medmemremapper MEDMEM::MEDMEM_REMAPPER
41 \section overview Overview
43 \c MEDMEM_REMAPPER enables conservative remapping of fields
44 between two sequential codes.
45 The computation is possible for 3D meshes and 2D meshes or 3D surfaces. It enables fast sequential localization, based on a bounding box tree structure. It is based on cell-cell intersection or on a point in element search, depending on the field type. Fields can either lie on cells (P0) or nodes (P1).
47 A typical use of \c MEDMEM_REMAPPER encompasses two distinct phases :
48 - A setup phase during which the intersection volumes are computed and the interpolation matrix is stored. This corresponds to calling the \c MEDMEM_REMAPPER::prepare() method.
49 - A use phase during which the remappings are actually performed. This corresponds to the calls to transfer() and reverseTransfer() which actually performs the interpolation.
51 The following code excerpt illutrates a typical use of the \c MEDMEM_REMAPPER class.
55 std::string sourceFileName("source.med");
56 MEDMEM::MESH med_source_mesh(MED_DRIVER,sourceFileName,"Source_Mesh");
57 std::string targetFileName("target.med");
58 MEDMEM::MESH med_target_mesh(MED_DRIVER,targetFileName,"Target_Mesh");
59 FIELD<double> sourceField(MED_DRIVER,sourceFileName,"Density",0,0);
60 FIELD<double> targetField;
61 MEDMEM_Remapper mapper;
62 mapper.setOptionsDouble("Precision",1e-7);
63 mapper.setOptionsString("Intersection_type",Geometric2D);
64 mapper.prepare(med_source_mesh,med_target_mesh,"P0P1");
65 mapper.transfer(sourceField,targetField);
73 MEDMEM_REMAPPER::MEDMEM_REMAPPER():_matrix(0),_sourceMesh(0), _targetMesh(0), _sourceSupport(0), _targetSupport(0)
77 MEDMEM_REMAPPER::~MEDMEM_REMAPPER()
81 _sourceMesh->removeReference();
83 _targetMesh->removeReference();
85 // _sourceSupport->removeReference();
87 // _targetSupport->removeReference();
89 /*! This method computes the intersection matrix between
90 * source \a mesh_source and \a mesh_target. It is a preliminary step
91 * that is necessary before calling the \c transfer() method.
92 * The method analyses the dimensions of the meshes and checks for compatibility.
95 int MEDMEM_REMAPPER::prepare(const MEDMEM::MESH& mesh_source, const MEDMEM::MESH& mesh_target, const char *method)
97 const int sm_spacedim = mesh_source.getSpaceDimension();
98 const int tm_spacedim = mesh_target.getSpaceDimension();
99 int sm_meshdim = mesh_source.getMeshDimension();
100 int tm_meshdim = mesh_target.getMeshDimension();
103 _matrix= new INTERP_KERNEL::Matrix<double,INTERP_KERNEL::ALL_FORTRAN_MODE>;
106 _sourceMesh->removeReference();
107 _sourceMesh= new MEDMEM::MESH((MEDMEM::MESH&)mesh_source);
109 _targetMesh->removeReference();
110 _targetMesh= new MEDMEM::MESH((MEDMEM::MESH&)mesh_target);
112 std::string methodC=method;
113 if(methodC == "P0P0"){
114 _sourceFieldType = "P0";
115 _targetFieldType = "P0";
117 else if(methodC =="P0P1"){
118 _sourceFieldType = "P0";
119 _targetFieldType = "P1";
121 else if(methodC == "P1P0"){
122 _sourceFieldType = "P1";
123 _targetFieldType = "P0";
125 else if(methodC == "P1P1"){
126 _sourceFieldType = "P1";
127 _targetFieldType = "P1";
130 throw INTERP_KERNEL::Exception("MEDMEM_REMAPPER::prepare: Invalid method specified ! Must be in : \"P0P0\" \"P0P1\" \"P1P0\" or \"P1P1\"");
133 // if(_sourceSupport)
134 // _sourceSupport->removeReference();
135 // if(_targetSupport)
136 // _targetSupport->removeReference();
137 if( _sourceFieldType == "P0")
138 _sourceSupport = ((MEDMEM::MESH *)_sourceMesh)->getSupportOnAll(MED_EN::MED_CELL);
140 _sourceSupport = ((MEDMEM::MESH *)_sourceMesh)->getSupportOnAll(MED_EN::MED_NODE);
141 if( _targetFieldType == "P0")
142 _targetSupport = ((MEDMEM::MESH *)_targetMesh)->getSupportOnAll(MED_EN::MED_CELL);
144 _targetSupport = ((MEDMEM::MESH *)_targetMesh)->getSupportOnAll(MED_EN::MED_NODE);
146 if (tm_spacedim!=sm_spacedim || tm_meshdim!=sm_meshdim)
147 throw MEDEXCEPTION("incompatible mesh and/or space dimensions in meshes");
148 if ((sm_spacedim==2)&&(sm_meshdim==2))
150 MEDNormalizedUnstructuredMesh<2,2> source_mesh_wrapper(_sourceMesh);
151 MEDNormalizedUnstructuredMesh<2,2> target_mesh_wrapper(_targetMesh);
152 INTERP_KERNEL::Interpolation2D interpolation(*this);
153 _nb_cols = interpolation.interpolateMeshes(source_mesh_wrapper,target_mesh_wrapper,*_matrix,method);
155 else if ((sm_spacedim==3)&&(sm_meshdim==3))
157 MEDNormalizedUnstructuredMesh<3,3> source_mesh_wrapper(_sourceMesh);
158 MEDNormalizedUnstructuredMesh<3,3> target_mesh_wrapper(_targetMesh);
159 INTERP_KERNEL::Interpolation3D interpolation(*this);
160 _nb_cols = interpolation.interpolateMeshes(source_mesh_wrapper,target_mesh_wrapper,*_matrix,method);
162 else if ((sm_spacedim==3)&&(sm_meshdim==2))
164 MEDNormalizedUnstructuredMesh<3,2> source_mesh_wrapper(_sourceMesh);
165 MEDNormalizedUnstructuredMesh<3,2> target_mesh_wrapper(_targetMesh);
166 INTERP_KERNEL::Interpolation3DSurf interpolation(*this);
167 _nb_cols = interpolation.interpolateMeshes(source_mesh_wrapper,target_mesh_wrapper,*_matrix,method);
170 throw MEDEXCEPTION("no Interpolation exists for the given mesh and space dimensions");
172 _nb_rows=(*_matrix).getNbRows();
174 _deno_multiply.resize(_nb_rows);
175 _matrix->rowSum(_deno_multiply);
176 _deno_reverse_multiply.resize(_nb_cols);
177 _matrix->colSum(_deno_reverse_multiply, _nb_cols);
184 remaps a vector source field defined on the source mesh onto the target mesh using the intersection matrix
185 \param field_source : source field to be remapped
186 \param target_field : field resulting from the remapping on the target mesh
188 void MEDMEM_REMAPPER::transfer(const MEDMEM::FIELD<double>& field_source, MEDMEM::FIELD<double>& field_target)
190 int source_nbcomp=field_source.getNumberOfComponents();
191 int nb_source_values= field_source.getNumberOfValues();
192 const double* value_source = field_source.getValue();
194 int target_nbcomp=field_target.getNumberOfComponents();
195 double* value_target = const_cast<double*> (field_target.getValue());
197 double precision = getPrecision();
199 if (source_nbcomp != target_nbcomp)
200 throw MEDMEM::MEDEXCEPTION("MEDMEM_REMAPPER::transfer: incoherent number of components for source and target fields");
201 if (_nb_cols != nb_source_values)
202 throw MEDMEM::MEDEXCEPTION("MEDMEM_REMAPPER::transfer: incoherent number of field values, cannot cannot multiply by interpolation matrix");
204 _matrix->multiply(value_source, value_target,source_nbcomp);
206 for (int i=0; i< _nb_rows; i++)
207 if(fabs(_deno_multiply[i]) > precision)
208 for(int comp = 0; comp < source_nbcomp; comp++)
209 value_target[i*source_nbcomp+comp]/=_deno_multiply[i];
211 for(int comp = 0; comp < source_nbcomp; comp++)
212 value_target[i*source_nbcomp+comp]=0.;
216 reverses the direct transfer remapping: a Vector field supported on the target mesh is remapped onto
217 the source mesh using the transpose of the intersection matrix
218 \param field_target : target field to be remapped
219 \param source_field : field resulting from the remapping on the source mesh
221 void MEDMEM_REMAPPER::reverseTransfer( MEDMEM::FIELD<double>& field_source, const MEDMEM::FIELD<double>& field_target)
223 int source_nbcomp=field_source.getNumberOfComponents();
224 double* value_source = const_cast<double*> (field_source.getValue());
226 int target_nbcomp=field_target.getNumberOfComponents();
227 int nb_target_values= field_target.getNumberOfValues();
228 const double* value_target = field_target.getValue();
230 double precision = getPrecision();
232 if (source_nbcomp != target_nbcomp)
233 throw MEDMEM::MEDEXCEPTION(" MEDMEM_REMAPPER::reverseTransfer: incoherent number of components for source and target fields");
234 if (_nb_rows != nb_target_values)
235 throw MEDMEM::MEDEXCEPTION(" MEDMEM_REMAPPER::reverseTransfer: incoherent number of field values, cannot cannot multiply by interpolation matrix");
237 _matrix->transposeMultiply(value_target, value_source, _nb_cols,target_nbcomp);//transposeMultiply(input,output, nbcols,nbcomp)
239 for (int i=0; i< _nb_cols; i++)
240 if(fabs(_deno_reverse_multiply[i]) > precision)
241 for(int comp = 0; comp < target_nbcomp; comp++)
242 value_source[i*target_nbcomp+comp]/=_deno_reverse_multiply[i];
244 for(int comp = 0; comp < target_nbcomp; comp++)
245 value_source[i*target_nbcomp+comp]=0.;
249 remaps a vector source field defined on the source mesh onto the target mesh using the intersection matrix
250 \param field_source : source field to be remapped
251 \return : field resulting from the remapping on the target mesh
253 MEDMEM::FIELD<double> * MEDMEM_REMAPPER::transferField(const MEDMEM::FIELD<double>& field_source)
255 int source_nbcomp=field_source.getNumberOfComponents();
256 const double* value_source = field_source.getValue();
257 int nb_source_values= field_source.getNumberOfValues();
259 double precision = getPrecision();
261 if (_nb_cols != nb_source_values)
262 throw MEDMEM::MEDEXCEPTION("MEDMEM_REMAPPER::transfer: incoherent number of field values, cannot cannot multiply by interpolation matrix");
264 MEDMEM::FIELD<double> * target_field = new MEDMEM::FIELD<double>(_targetSupport,source_nbcomp);
265 double* value_target = const_cast<double*> ((*target_field).getValue());
267 _matrix->multiply(value_source, value_target,source_nbcomp);
269 for (int i=0; i< _nb_rows; i++)
270 if(fabs(_deno_multiply[i]) > precision)
271 for(int comp = 0; comp < source_nbcomp; comp++)
272 value_target[i*source_nbcomp+comp]/=_deno_multiply[i];
274 for(int comp = 0; comp < source_nbcomp; comp++)
275 value_target[i*source_nbcomp+comp]=0.;
281 reverses the direct transfer remapping: a Vector field supported on the target mesh is remapped onto
282 the source mesh using the transpose of the intersection matrix
283 \param field_target : target field to be remapped
284 \return : field resulting from the remapping on the source mesh
286 MEDMEM::FIELD<double> * MEDMEM_REMAPPER::reverseTransferField(const MEDMEM::FIELD<double>& field_target)
288 int target_nbcomp=field_target.getNumberOfComponents();
289 const double* value_target = field_target.getValue();
290 int nb_target_values= field_target.getNumberOfValues();
292 double precision = getPrecision();
294 if (_nb_rows != nb_target_values)
295 throw MEDMEM::MEDEXCEPTION(" MEDMEM_REMAPPER::reverseTransfer: incoherent number of field values, cannot cannot transpose-multiply by interpolation matrix");
297 MEDMEM::FIELD<double> * source_field = new MEDMEM::FIELD<double>(_sourceSupport,target_nbcomp);
298 double* value_source = const_cast<double*> ((*source_field).getValue());
300 _matrix->transposeMultiply(value_target, value_source, _nb_cols,target_nbcomp);//transposeMultiply(input,output, nbcols,nbcomp)
302 for (int i=0; i< _nb_cols; i++)
303 if(fabs(_deno_reverse_multiply[i]) > precision)
304 for(int comp = 0; comp < target_nbcomp; comp++)
305 value_source[i*target_nbcomp+comp]/=_deno_reverse_multiply[i];
307 for(int comp = 0; comp < target_nbcomp; comp++)
308 value_source[i*target_nbcomp+comp]=0.;
313 int MEDMEM_REMAPPER::setOptionDouble(const std::string& key, double value)
315 bool result = INTERP_KERNEL::InterpolationOptions::setOptionDouble(key,value);
323 int MEDMEM_REMAPPER::setOptionInt(const std::string& key, int value)
325 bool result = INTERP_KERNEL::InterpolationOptions::setOptionInt(key,value);
333 int MEDMEM_REMAPPER::setOptionString(const std::string& key, std::string& value)
335 bool result = INTERP_KERNEL::InterpolationOptions::setOptionString(key,value);
344 \brief returns the volumes of the cells underlying the support \a support
346 For 2D geometries, the returned field contains the areas.
347 For 3D geometries, the returned field contains the volumes.
349 \param support : support whose cell volumes are required
350 \return field containing the volumes
352 MEDMEM::FIELD<double>* MEDMEM_REMAPPER::getSupportVolumes(const MEDMEM::SUPPORT& support)
354 const MEDMEM::GMESH* mesh=support.getMesh();
355 int dim = mesh->getMeshDimension();
359 return mesh->getArea(&support);
361 return mesh->getVolume(&support);
363 throw MEDMEM::MEDEXCEPTION("interpolation is not available for this dimension");
367 void MEDMEM_REMAPPER::printMatrixInfo()
369 std::cout << *_matrix << std::endl;