TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Convert_ICoCoTrioField.cpp
1/****************************************************************************
2* Copyright (c) 2025, CEA
3* All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
6* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
7* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8* 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
9*
10* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
11* IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
12* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
13*
14*****************************************************************************/
15
16#include <Convert_ICoCoTrioField.h>
17#include <ICoCoTrioField.h>
18#include <ICoCoMEDDoubleField.hxx>
19#include <Domaine.h>
20#include <Champ_Generique_base.h>
21#include <Domaine_VF.h>
22#include <PE_Groups.h>
23#include <Comm_Group.h>
24#include <Polyedre.h>
25
26void affecte_double_avec_doubletab(double** p, const ArrOfDouble& trio)
27{
28 *p=new double[trio.size_array()];
29 memcpy(*p,trio.addr(),trio.size_array()*sizeof(double));
30}
31
32void affecte_int_avec_inttab(int** p, const ArrOfInt& trio)
33{
34 int sz=trio.size_array();
35 *p=new int[sz];
36 memcpy(*p,trio.addr(),sz*sizeof(int));
37}
38
39void build_triofield(const Champ_Generique_base& ch, ICoCo::TrioField& afield)
40{
41 build_triomesh(ch.get_ref_domaine_dis_base(), afield, ch.get_localisation() == Entity::NODE, ch.get_localisation() == Entity::FACE);
42
43 afield.setName(ch.le_nom().getString());
44 afield._time1 = afield._time2 = ch.get_time(), afield._itnumber = 0;
45
46 /* copy of field values */
47 afield._has_field_ownership = true;
48 OWN_PTR(Champ_base) espace_stockage;
49 const Champ_base& champ_ecriture = ch.get_champ(espace_stockage);
50 const DoubleTab& vals = champ_ecriture.valeurs();
51 afield._nb_field_components = vals.nb_dim() > 1 ? vals.dimension(1) : 1;
52 affecte_double_avec_doubletab(&afield._field, vals);
53}
54
55void build_triofield(const Champ_base& ch, const Domaine_dis_base& dom_dis, ICoCo::TrioField& afield)
56{
57 build_triomesh(dom_dis, afield, 0, 0); // XXX seulement elem...
58
59 afield.setName(ch.le_nom().getString());
60 afield._time1 = afield._time2 = 0.0, afield._itnumber = 0;
61
62 /* copy of field values */
63 afield._has_field_ownership = true;
64 const DoubleTab& vals = ch.valeurs();
65 afield._nb_field_components = vals.nb_dim() > 1 ? vals.dimension(1) : 1;
66 affecte_double_avec_doubletab(&afield._field, vals);
67}
68
69void build_triomesh(const Domaine_dis_base& dom_dis, ICoCo::TrioField& afield, int type, int loc_faces)
70{
71 const Domaine_VF& zvf = ref_cast(Domaine_VF, dom_dis);
72 const Domaine& dom = dom_dis.domaine();
73 afield.clear();
74 afield._type = type;
75
76 /* node array: copy from the domain */
77 const DoubleTab& coord = dom.les_sommets();
78 afield._space_dim = dom.dimension;
79 afield._nbnodes = coord.dimension(0);
80 affecte_double_avec_doubletab(&afield._coords, coord);
81
82 /* dimension of the domain elements */
83 Motcle type_elem_ = dom_dis.domaine().type_elem()->que_suis_je();
84 Motcle type_elem(type_elem_);
85 type_elem.prefix("_AXI");
86 if (type_elem != Motcle(type_elem_))
87 {
88 if (type_elem == "QUADRILATERE_2D")
89 type_elem = "SEGMENT_2D";
90 if (type_elem == "RECTANGLE_2D")
91 type_elem = "RECTANGLE";
92 }
93 if ((type_elem == "RECTANGLE") || (type_elem == "QUADRANGLE") || (type_elem == "TRIANGLE") || (type_elem == "TRIANGLE_3D") || (type_elem == "QUADRANGLE_3D") || (type_elem == "POLYGONE") || (type_elem == "POLYGONE_3D"))
94 afield._mesh_dim=2;
95 else if ((type_elem == "HEXAEDRE") || (type_elem == "HEXAEDRE_VEF") || (type_elem == "POLYEDRE") || (type_elem == "PRISME") || (type_elem == "TETRAEDRE"))
96 afield._mesh_dim=3;
97 else if ((type_elem == "SEGMENT_2D") || (type_elem == "SEGMENT"))
98 afield._mesh_dim=1;
99 else
100 {
101 Cerr << "build_triofield: " << type_elem<< " not coded" <<finl;
103 }
104
105 /* elements: those of the domain if the field is at nodes/elements, or faces if the field is at faces */
106 if (loc_faces) afield._mesh_dim--;
107 afield._nb_elems = loc_faces ? zvf.nb_faces() : dom_dis.domaine().nb_elem();
108 if (loc_faces || type_elem != "POLYEDRE") //face mesh -> connectivity = face_sommets
109 {
110 const IntTab& conn = loc_faces ? dom_dis.face_sommets() : dom_dis.domaine().les_elems();
111 //the only way to prevent polygons from being mistaken for quadrilaterals is to have a connectivity array of width > 4...
112 afield._nodes_per_elem = std::max(conn.dimension(1), type_elem == "POLYGONE" || type_elem == "POLYGONE_3D" || type_elem == "POLYEDRE" ? (int) 5 : 0);
113 afield._connectivity = new int[afield._nb_elems * afield._nodes_per_elem];
114 for (int i = 0; i < afield._nb_elems; i++)
115 for (int j = 0; j < afield._nodes_per_elem; j++)
116 afield._connectivity[afield._nodes_per_elem * i + j] = j < conn.dimension(1) ? conn(i, j) : -1;
117 }
118 else //polyhedron mesh -> connectivity in MEDCoupling format, to be built manually
119 {
120 const Polyedre& poly = ref_cast(Polyedre, dom.type_elem().valeur());
121 const ArrOfInt& e_fi = poly.getPolyhedronIndex(), &f_si = poly.getFacesIndex(), &sl = poly.getNodes();
122 const IntTab& e_s = dom.les_elems();
123 int e, f, s, nef_max = 0, nfs_max = 0; //max nb faces/elem and nodes/face
124 for (e = 0; e + 1 < e_fi.size_array(); e++) nef_max = std::max(nef_max, e_fi(e + 1) - e_fi(e));
125 for (f = 0; f + 1 < f_si.size_array(); f++) nfs_max = std::max(nfs_max, f_si(f + 1) - f_si(f));
126 afield._nodes_per_elem = std::max(nef_max * (nfs_max + 1), (int) 9); //one -1 after each face: at least 9 to avoid butterfly cells
127 int *p = afield._connectivity = new int[afield._nb_elems * afield._nodes_per_elem];
128 for (e = 0; e < afield._nb_elems; e++)
129 {
130 /* insertion of the connectivity of each face, followed by a -1 */
131 for (f = e_fi(e); f < e_fi(e + 1); f++, *p = -1, p++)
132 for (s = f_si(f); s < f_si(f + 1); s++)
133 *p = e_s(e, sl(s)), p++;
134 /* fill with -1 up to the next row */
135 for ( ; p < afield._connectivity + (e + 1) * afield._nodes_per_elem; p++) *p = -1;
136 }
137 }
138}
139
140#ifndef NO_MEDFIELD
141#include <MEDCouplingUMesh.hxx>
142#include <MEDCouplingFieldDouble.hxx>
143#include <MCAuto.hxx>
144#include <string.h>
145#include <vector>
146
147
148using ICoCo::TrioField;
149using ICoCo::MEDDoubleField;
150using std::vector;
151
152
153/*!
154 * @brief Build a MEDDoubleField from a TrioField.
155 *
156 * This method is non const only due to this->_field that can be modified (to point to the same domaine than returned object).
157 * So \b warning, to access to \a this->_field only when the returned object is alive.
158 * @param triofield the TrioField to convert
159 * @return the corresponding MEDDoubleField
160 */
161MEDDoubleField build_medfield(TrioField& triofield)
162{
163 MEDCoupling::MCAuto<MEDCoupling::MEDCouplingUMesh> mesh(MEDCoupling::MEDCouplingUMesh::New("",triofield._mesh_dim));
164 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> coo(MEDCoupling::DataArrayDouble::New());
165 coo->alloc(triofield._nbnodes,triofield._space_dim);
166 mesh->setCoords(coo);
167 double *ptr(coo->getPointer());
168 std::copy(triofield._coords,triofield._coords+triofield._space_dim*triofield._nbnodes,ptr);
169 mesh->allocateCells(triofield._nb_elems);
170 INTERP_KERNEL::NormalizedCellType elemtype;
171 switch(triofield._mesh_dim)
172 {
173 case 0 :
174 {
175 switch (triofield._nodes_per_elem)
176 {
177 case 0: // cas field vide
178 elemtype=INTERP_KERNEL::NORM_SEG2; // to avoid warning
179 break;
180 default:
181 throw INTERP_KERNEL::Exception("incompatible Trio field - wrong nb of nodes per elem");
182 }
183 break;
184 }
185 case 1:
186 {
187 switch (triofield._nodes_per_elem)
188 {
189 case 2:
190 elemtype=INTERP_KERNEL::NORM_SEG2;
191 break;
192 default:
193 throw INTERP_KERNEL::Exception("incompatible Trio field - wrong nb of nodes per elem");
194 }
195 break;
196 }
197 case 2:
198 {
199 switch (triofield._nodes_per_elem)
200 {
201 case 3:
202 elemtype=INTERP_KERNEL::NORM_TRI3;
203 break;
204 case 4 :
205 elemtype=INTERP_KERNEL::NORM_QUAD4;
206 break;
207 default:
208 elemtype=INTERP_KERNEL::NORM_POLYGON;
209 }
210 break;
211 }
212 case 3:
213 {
214 switch (triofield._nodes_per_elem)
215 {
216 case 4:
217 elemtype=INTERP_KERNEL::NORM_TETRA4;
218 break;
219 case 8 :
220 elemtype=INTERP_KERNEL::NORM_HEXA8;
221 break;
222 default:
223 elemtype=INTERP_KERNEL::NORM_POLYHED;
224 }
225 break;
226 default:
227 throw INTERP_KERNEL::Exception("incompatible Trio field - wrong mesh dimension");
228 }
229 }
230 //creating a connectivity table that complies to MED (1 indexing) <- actually no
231 //and passing it to _mesh
232 MEDCoupling::MCAuto<MEDCoupling::MEDCouplingFieldDouble> field;
233 int *conn(new int[triofield._nodes_per_elem]);
234 for (int i=0; i<triofield._nb_elems; i++)
235 {
236
237 for(int j=0; j<triofield._nodes_per_elem; j++)
238 {
239 conn[j]=triofield._connectivity[i*triofield._nodes_per_elem+j];
240 }
241 if (elemtype==INTERP_KERNEL::NORM_QUAD4)
242 {
243 // different node ordering in TRUST
244 int tmp=conn[3];
245 conn[3]=conn[2];
246 conn[2]=tmp;
247 }
248 if (elemtype==INTERP_KERNEL::NORM_HEXA8)
249 {
250 // different node ordering in TRUST
251 int tmp=conn[3];
252 conn[3]=conn[2];
253 conn[2]=tmp;
254 tmp=conn[7];
255 conn[7]=conn[6];
256 conn[6]=tmp;
257 }
258 int size = triofield._nodes_per_elem;
259 while (conn[size - 1] == -1) size--; //remove trailing -1 values from connectivity
260#if INT_is_64_ == 2
261 // Convert int into mcIdType
262 std::vector<mcIdType> conn_mc(conn, conn+size);
263 mesh->insertNextCell(elemtype,size,conn_mc.data());
264#else
265 mesh->insertNextCell(elemtype,size,conn);
266#endif
267 }
268 delete [] conn;
269 mesh->finishInsertingCells();
270 //
271
272
273 std::vector<int> cells;
274 // if ((mesh->getSpaceDimension() == 2 || mesh->getSpaceDimension() == 3) && mesh->getMeshDimension() == 2)
275 // mesh->checkButterflyCells(cells);
276 if (!cells.empty())
277 {
278 Cerr<<" cells are butterflyed "<<cells[0]<<finl;
282 }
283 //field on the sending end
284 int nb_case=triofield.nb_values();
285 if (triofield._type==0)
286 {
287 field = MEDCoupling::MEDCouplingFieldDouble::New(MEDCoupling::ON_CELLS,MEDCoupling::ONE_TIME);
288 }
289 else
290 {
291 field = MEDCoupling::MEDCouplingFieldDouble::New(MEDCoupling::ON_NODES,MEDCoupling::ONE_TIME );
292 }
293 field->setMesh(mesh);
294 field->setNature(MEDCoupling::IntensiveMaximum);
295 MEDCoupling::MCAuto<MEDCoupling::DataArrayDouble> fieldArr(MEDCoupling::DataArrayDouble::New());
296 fieldArr->alloc(field->getNumberOfTuplesExpected(),triofield._nb_field_components);
297 field->setName(triofield.getName());
298 std::string meshName("SupportOf_");
299 meshName+=triofield.getName();
300 mesh->setName(meshName);
301 field->setTime(triofield._time1,0,triofield._itnumber);
302 if (triofield._field!=0)
303 {
304 for (int i =0; i<nb_case; i++)
305 for (int j=0; j<triofield._nb_field_components; j++)
306 {
307 fieldArr->setIJ(i,j,triofield._field[i*triofield._nb_field_components+j]);
308 }
309 }
310 //field on the receiving end
311 else
312 {
313 // the trio field points to the pointer inside the MED field
314 triofield._field=fieldArr->getPointer();
315 for (int i=0; i<triofield._nb_field_components*nb_case; i++)
316 triofield._field[i]=0.0;
317 }
318 field->setArray(fieldArr);
319 return MEDDoubleField(field);
320}
321MEDDoubleField build_medfield(const Champ_Generique_base& ch)
322{
323 TrioField fl;
324 build_triofield(ch, fl);
325 return build_medfield(fl);
326}
327
328
329#else
330namespace ICoCo
331{
332class MEDDoubleField
333{
334};
335}
336ICoCo::MEDDoubleField build_medfield(ICoCo::TrioField& ch)
337{
338 Cerr<<"Version compiled without MEDCoupling"<<finl;
340 throw;
341}
342ICoCo::MEDDoubleField build_medfield(const Champ_Generique_base& ch)
343{
344 Cerr<<"Version compiled without MEDCoupling"<<finl;
346 throw;
347}
348#endif
class Champ_Generique_base
virtual const Domaine_dis_base & get_ref_domaine_dis_base() const
Returns a ref to the discretized domain on which the storage space will be evaluated.
virtual const Champ_base & get_champ(OWN_PTR(Champ_base) &espace_stockage) const =0
virtual double get_time() const
Returns the time of the Champ_Generique_base.
virtual Entity get_localisation(const int index=-1) const
Returns the type of geometric entities on which the discrete values are attached (NODE for a P1 field...
virtual DoubleTab & valeurs()=0
class Champ_base This class is the base of the fields hierarchy.
Definition Champ_base.h:43
virtual void abort() const =0
virtual void clear()
Reset the Domaine completely except for its name.
Definition Domaine.cpp:108
DoubleTab_t & les_sommets()
Definition Domaine.h:113
IntTab_t & les_elems()
Definition Domaine.h:129
int_t nb_elem() const
Definition Domaine.h:131
class Domaine_VF
Definition Domaine_VF.h:44
int nb_faces() const
Returns the total number of faces.
Definition Domaine_VF.h:471
class Domaine_dis_base This class is the base of the hierarchy of discretized domains.
virtual IntTab & face_sommets()
const Domaine & domaine() const
const Nom & le_nom() const override
Returns the name of the field.
A character string (Nom) in uppercase.
Definition Motcle.h:26
const std::string & getString() const
Definition Nom.h:92
static int dimension
Definition Objet_U.h:94
const Nom & que_suis_je() const
Returns the string identifying the class.
Definition Objet_U.cpp:104
virtual const Nom & le_nom() const
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
Definition Objet_U.cpp:317
static const Comm_Group & groupe_TRUST()
Returns a reference to the group containing all TRUST processors.
const ArrOfInt_t & getPolyhedronIndex() const
Definition Polyedre.h:69
const BigArrOfInt_t & getNodes() const
Definition Polyedre.h:67
const ArrOfInt_t & getFacesIndex() const
Definition Polyedre.h:75
static void abort()
Abort routine for TRUST on a fatal error.
Definition Process.cpp:573
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
_SIZE_ size_array() const
_TYPE_ * addr()
int nb_dim() const
Definition TRUSTTab.h:199
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133