TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Champ_Fonc_MED.cpp
1/****************************************************************************
2* Copyright (c) 2026, 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 <Champ_Fonc_MED.h>
17#include <LireMED.h>
18#include <Char_ptr.h>
19#include <EFichier.h>
20#include <EChaine.h>
21#include <medcoupling++.h>
22#include <TRUST_2_MED.h>
23#include <Comm_Group_MPI.h>
24#ifdef MEDCOUPLING_
25#include <MEDLoader.hxx>
26#include <MEDCouplingField.hxx>
27#include <MEDCouplingFieldDouble.hxx>
28#ifdef MPI_
29#include <ParaMEDFileMesh.hxx>
30#endif
31#pragma GCC diagnostic ignored "-Wreorder"
32#include <MEDFileField.hxx>
33#include <communications.h>
34
35using MEDCoupling::MEDCouplingField;
36using MEDCoupling::MEDCouplingFieldDouble;
37using MEDCoupling::MCAuto;
38using MEDCoupling::DataArrayIdType;
39using MEDCoupling::GetTimeAttachedOnFieldIteration;
40using MEDCoupling::GetAllFieldNamesOnMesh;
41using MEDCoupling::MEDFileFieldMultiTS;
42using MEDCoupling::MEDFileField1TS;
43using MEDCoupling::MEDFileMesh;
44#endif
45
46// XD champ_fonc_med field_base champ_fonc_med BRACE Field to read a data field in a MED-format file .med at a specified
47// XD_CONT time. It is very useful, for example, to resume a calculation with a new or refined geometry. The field
48// XD_CONT post-processed on the new geometry at med format is used as initial condition for the resume.
49Implemente_instanciable(Champ_Fonc_MED,"Champ_Fonc_MED",Champ_Fonc_base);
50
52{
53 return s << que_suis_je() << " " << le_nom();
54}
55
57{
58 param.ajouter_flag("use_existing_domain", &use_existing_domain_); // XD_ADD_P flag
59 // XD_CONT whether to optimize the field loading by indicating that the field is supported by the same mesh that was
60 // XD_CONT initially loaded as the domain
61 param.ajouter_flag("last_time", &last_time_only_); // XD_ADD_P flag
62 // XD_CONT to use the last time of the MED file instead of the specified time. Mutually exclusive with 'time'
63 // XD_CONT parameter.
64 param.ajouter("decoup", &nom_decoup_, Param::OPTIONAL); // XD_ADD_P chaine
65 // XD_CONT specify a partition file.
66 param.ajouter("mesh", &nom_maillage_, Param::OPTIONAL); // XD_ADD_P chaine
67 // XD_CONT Name of the mesh supporting the field. This is the name of the mesh in the MED file, and if this mesh was
68 // XD_CONT also used to create the TRUST domain, loading can be optimized with option 'use_existing_domain'.
69 param.ajouter("domain", &nom_dom_, Param::REQUIRED); // XD_ADD_P chaine
70 // XD_CONT Name of the domain supporting the field. This is the name of the mesh in the MED file, and if this mesh was
71 // XD_CONT also used to create the TRUST domain, loading can be optimized with option 'use_existing_domain'.
72 param.ajouter("file", &nom_fichier_med_, Param::REQUIRED); // XD_ADD_P chaine
73 // XD_CONT Name of the .med file.
74 param.ajouter("field", &nom_champ_, Param::REQUIRED); // XD_ADD_P chaine
75 // XD_CONT Name of field to load.
76 param.ajouter("loc", &loc_, Param::OPTIONAL); // XD_ADD_P chaine(into=["som","elem"])
77 // XD_CONT To indicate where the field is localised. Default to 'elem'.
78 param.ajouter("time", &temps_, Param::OPTIONAL); // XD_ADD_P double
79 // XD_CONT Timestep to load from the MED file. Mutually exclusive with 'last_time' flag.
80}
81
83{
84#ifdef MEDCOUPLING_
85 Nom chaine_lue;
86 bool nom_decoup_lu = false;
87 nom_decoup_ = "";
88
89 is>>chaine_lue;
90 if (chaine_lue == "{") // New syntax !!
91 {
92 Nom s = "{ ";
93 int cnt = 1;
94 while (cnt)
95 {
96 Nom motlu;
97 is >> motlu;
98 if (motlu == "{") cnt++;
99 if (motlu == "}") cnt --;
100 s += Nom(" ") + motlu;
101 }
102 Param param(que_suis_je());
103 set_param(param);
104
105 EChaine is2(s);
106 loc_ = "";
107 constexpr double MIN_INF = -1.0e+300;
108 temps_ = MIN_INF;
109 param.lire_avec_accolades(is2);
110 // Localisation is elem by default
111 if (loc_ == "") loc_ = "elem";
112 if (nom_decoup_ != "") nom_decoup_lu = true;
113 // At least one time needed!
114 if (!last_time_only_ && temps_ == MIN_INF) // no time was provided
115 {
116 Cerr << "ERROR: reading 'Champ_fonc_MED': no time was provided! Either 'last_time' or 'time' parameter must be specified!" << finl;
117 Process::exit(-1);
118 }
119 if (last_time_only_ && temps_ != MIN_INF) // too many time options
120 {
121 Cerr << "ERROR: reading 'Champ_fonc_MED': both 'time' and 'last_time' were provided! Choose only one!" << finl;
122 Process::exit(-1);
123 }
124
125 }
126 else // Old syntax?
127 {
128 Cerr << "ERROR: reading 'Champ_fonc_MED': Expected opening brace '{' - are you using the new syntax?" << finl;
129 Cerr << "If you are still using the old syntax (before TRUST v1.9.3), \nyou can use -convert_data option of your application script:" << finl;
130 Cerr << " trust -convert_data " << Objet_U::nom_du_cas() << ".data" << finl;
131 Process::exit(-1);
132 }
133
134 //
135 // Finished interpreting ... processing now:
136 //
137 if (!nom_decoup_lu)
138 nom_decoup_ = Nom("decoup/") + nom_dom_ + ".txt"; // default value for nom_decoup
139
140 traite_nom_fichier_med(nom_fichier_med_);
141 // Reading multiple .med files works: see test case Champ_fonc_MED_Parallele
142 // A check is performed below to verify that the partitions overlap correctly
143 int multiple_med = 0;
144 Nom tmp(nom_fichier_med_);
145 tmp.prefix("0001.med");
147 {
148 multiple_med = 1;
149 /*
150 // Adding a blocking test to prevent reading 000n.med files
151 Cerr << "Error, Champ_Fonc_MED can't read, for the moment, partitioned MED files." << finl;
152 Cerr << "Try to build a single MED file by:" << finl;
153 Cerr << "A) Using LATA format for the previous calculation." << finl;
154 Cerr << "B) Convert the LATA files into a single MED file with Lata_to_MED keyword." << finl;
155 Cerr << "C) Use this single MED file with Champ_Fonc_MED keyword." << finl;
156 exit(); */
157 }
158 multiple_med = mp_max(multiple_med);
160
161 int field_size;
162 bool domain_exist=( interprete().objet_existant(nom_dom_) && sub_type(Domaine, interprete().objet(nom_dom_)) );
164 {
165 if (!domain_exist)
166 {
167 Cerr << "The domain " << nom_dom_ << " does not exist !!!! In Champ_Fonc_MED " << nom_fichier_med_ << " " << nom_dom_
168 << " " << nom_champ_ << " " << loc_ << " " << temps_ << finl;
169 exit();
170 }
171 else
172 {
173 // use_existing_domain can be used in parallel only if process 0 manages the entire domain or if a partition file is specified:
174 const Domaine& le_domaine=ref_cast(Domaine, interprete().objet(nom_dom_));
175 if (Process::is_parallel() && mp_max((int)(le_domaine.nb_som()>0)) != 0 && !nom_decoup_lu)
176 {
177 Cerr << "Warning, you can't use use_existing_domain on a partitionned domain like " << nom_dom_ << finl;
178 Cerr << "It is not parallelized yet... So we use MED mesh, which is not optimal." << finl;
179 Cerr << "Try suppress use_existing_domain option." << finl;
180 //Process::exit();
181 use_existing_domain_ = false;
182 }
183 }
184 }
185 if (domain_exist && use_existing_domain_)
186 {
187 Cerr<<nom_dom_<<" was not read into the med file because it already exists." <<finl;
188
189 const Domaine& le_domaine=ref_cast(Domaine, interprete().objet(nom_dom_));
190
191#ifndef NDEBUG
192 // In debug, check that we really have the same domain.
193 // Only doable in sequential, since in //, dom=full_domain, un_dom=local_domain
194 if (nproc()==1)
195 {
196 Cerr << "Checking whether domain in the file "<<nom_fichier_med_<<" and domain "<<nom_dom_<<" are the same (coords,connectivity) ..."<<finl;
197 LireMED liremed(nom_fichier_med_, nom_maillage_ == "??" ? nom_dom_ : nom_maillage_);
198 dom_med_.nommer(nom_dom_);
199 liremed.associer_domaine(dom_med_);
200 liremed.retrieve_MC_objects();
201 const MEDCouplingUMesh* new_um = liremed.get_mc_mesh();
202 const MEDCouplingUMesh* root_um = le_domaine.get_mc_mesh();
203 try
204 {
205 DataArrayIdType *dnup1=nullptr, *dnup2=nullptr;
206 // Less strict checkGeoEquivalWith (levOfCheck = 12 instead of 2). we use now "nodal" comparison.
207 // Two cells are considered equal if they are based on same nodes and have the same type.
208 // This is the weakest policy, it can be used by users not sensitive to cell orientation.
209 // if levOfCheck set to 2, some F5 and G3 tests fail
210
211 root_um->checkGeoEquivalWith(new_um, /* levOfCheck= */ 12, Objet_U::precision_geom, dnup1, dnup2);
212 //MCAuto<DataArrayIdType> dnu1(dnup1), dnu2(dnup2);
213 if (dnup2) dnup2->decrRef();
214 if (dnup1) dnup1->decrRef();
215 }
216 catch(INTERP_KERNEL::Exception& e)
217 {
218 Cerr << "Comparison of the two domains failed, with the following message from MEDCoupling::checkGeoEquivalWith()" << finl;
219 Cerr << e.what() << finl;
221 }
222 dom_med_=Domaine(); // Reset
223 }
224#endif
225 field_size = creer(nom_fichier_med_,le_domaine,loc_,temps_sauv_);
226 }
227 else
228 {
229 if (domain_exist && !use_existing_domain_)
230 Cerr<<"INFO: You can toggle the flag 'use_existing_domain' in 'Champ_Fonc_MED' to optimize reading since it seems that the domain already exists."<<finl;
231 LireMED liremed(nom_fichier_med_, nom_maillage_ == "??" ? nom_dom_ : nom_maillage_);
232 dom_med_.nommer(nom_dom_);
233 //Nom nom_dom_trio_non_nomme;
234 // Remplit dom:
235 liremed.associer_domaine(dom_med_);
236 liremed.lire_geom(false); // false: do not create sub-dom files
237 if (multiple_med)
238 {
239 // Check that the overlaps are identical (imperfect check based on BoundingBox)
240 DoubleTab BB1 = dom_med_.getBoundingBox();
241 const Domaine& dom_calcul = ref_cast(Domaine, interprete().objet(nom_dom_));
242 DoubleTab BB2 = dom_calcul.getBoundingBox();
243 for (int i=0; i<dimension; i++)
244 for (int j=0; j<2; j++)
245 if (est_different(BB1(i,j), BB2(i,j)))
246 {
247 Cerr << "Error, Champ_Fonc_MED can't read the partitionned MED files." << finl;
248 Cerr << "=> it seems that the MED partition is different than the '" << dom_calcul.le_nom() << "' domain partition." << finl;
250 }
251 Cerr << "Ok MED partition matches the domain partition so reading multiple MED files..." << finl;
252 }
253 // MODIF ELI LAUCOIN (06/03/2012):
254 // adding the attribute temps_sauv_
256 }
257 if (last_time_only_)
258 {
259 temps_=temps_sauv_[temps_sauv_.size_array()-1];
260 Cout << "The resumption time is "<<temps_<<finl;
261 }
262 // END MODIF ELI LAUCOIN (06/03/2012)
263 /* in parallel mode: create the filter */
264 if (Process::is_parallel() && field_size < 0)
265 {
266 EFichier fdec;
267 fdec.ouvrir(nom_decoup_);
268 // Case where the .med file mesh follows the numbering of the initial mesh (requires the partition file to recover the numbering)
269 if (fdec.good())
270 {
271 int dec_size=-1;
272 if(loc_ == "elem")
273 {
274 ArrOfInt dec;
275 fdec >> dec;
276 dec_size = dec.size_array();
277 for (int i = 0; i < dec_size; i++)
278 if (dec[i] == Process::me()) filter.push_back(i);
279 }
280 else if(loc_ == "som")
281 {
282 int nbNodes;
283 fdec >> nbNodes;
284 std::vector<std::set<int>> dec(nbNodes);
285 for(int n=0; n<nbNodes; n++)
286 {
287 int node,size;
288 fdec >> node >> size;
289 for(int p=0; p<size; p++)
290 {
291 int proc;
292 fdec >> proc;
293 dec[node].insert(proc);
294 }
295 }
296 dec_size = (int)dec.size();
297 for (int n=0; n < dec_size; n++)
298 for(std::set<int>::iterator it = dec[n].begin(); it!=dec[n].end(); ++it)
299 if (*it == Process::me()) filter.push_back(n);
300 }
301 else
302 {
303 Cerr << "Champ_Fonc_MED on parallel domain : decoup file only handled for field located on nodes or on cells!" << finl;
305 }
306 }
307 else // Case where the .med mesh follows the numbering of the partitioned mesh
308 {
309 int nb_item = le_champ().valeurs().dimension(0);
310 trustIdType first_item = mppartial_sum(nb_item);
311 for (int i=0; i<nb_item; i++)
312 filter.push_back(first_item);
313 }
314 Cerr << "Creating a filter to access efficiently values in " << nom_fichier_med_ << finl;
315 if ((int) filter.size() != le_champ().valeurs().dimension(0))
316 {
317 Cerr << "Champ_Fonc_MED on parallel domain : inconsistency between filter and domain (not the same number of entities)!" << finl;
319 }
320 }
321 else if (field_size != le_champ().valeurs().dimension(0))
322 {
323 Cerr << "Champ_Fonc_MED on existing domain : inconsistency between domain file and field (not the same number of entities)!" << finl;
325 }
329#endif
330
331 return is ;
332}
333
335{
336 if (t<0)
337 {
338 // If t is negative: convention (not documented in TRUST) to specify a time step number:
339 int given_it = -(int) t - 1;
340 lire(-1, given_it);
341 }
342 else
343 lire(t);
344}
345
346#ifdef MED_
347med_geometry_type type_geo_trio_to_type_med(const Nom& type);
348#ifdef MEDCOUPLING_
349INTERP_KERNEL::NormalizedCellType type_geo_trio_to_type_medcoupling(const Nom& type, int& mesh_dimension);
350#endif
351#endif
352
353void Champ_Fonc_MED::lire(double t, int given_it)
354{
355 if (domainebidon_inst.nb_elem()==0) // Empty domain case
356 {
357 // Update:
359 le_champ().Champ_Fonc_base::mettre_a_jour(t);
360 return;
361 }
362#ifdef MED_
363#ifdef MEDCOUPLING_
364 // Read a field
365 std::string meshName = nom_maillage_ == Nom() ? mon_dom->le_nom().getString() : nom_maillage_.getString();
366 std::string fieldName = nom_champ_dans_fichier_med_.getString();
367 std::string fileName = nom_fichier_med_.getString();
368 // Determine whether to search for the field in the MED file:
369 bool search_field = true;
370 nb_dt = temps_sauv_.size_array();
371 if (nb_dt>0)
372 {
373 // nb_dt: number of time steps in the MED file
374 // ndt: size of the temps_sauv array containing the time steps of the field in the MED file
375 // tmax: last time in the temps_sauv array
376 // dt: last time step in the temps_sauv array
377 // t: current time for which the field is to be filled
378 // last_time_only_: specified in the dataset or not
379 double tmax = temps_sauv_[nb_dt - 1];
380 double dt = temps_sauv_[nb_dt - 1];
381 if (((nb_dt == 1) && (!est_egal(dt, t))) || ((last_time_only_) && (!est_egal(tmax, t))))
382 {
383 Cout << "We assume that the field " << fieldName << " is stationary." << finl;
384 search_field = false;
385 }
386 }
387 if (search_field)
388 {
389 if (temps_sauv_.size_array()==0)
390 temps_sauv_ = lire_temps_champ(fileName, fieldName);
391 unsigned int nn = temps_sauv_.size_array();
392 if (given_it == -1)
393 {
394 for (given_it = 0; given_it < (int) nn; given_it++)
395 if (est_egal(temps_sauv_[given_it], t)) break;
396 if (given_it == (int)nn)
397 {
398 Cerr << "Error. Time " << t << " not found in the times list of the " << fileName << " file" << finl;
399 for (unsigned int n=0; n<nn; n++)
400 Cerr << temps_sauv_[n] << finl;
402 }
403 }
404 int iteration = time_steps_[given_it].first;
405 int order = time_steps_[given_it].second;
406
407 if(filter.size()) // Partial reading of field (only field values are loaded, not its structure!)
408 {
409#ifdef MPI_
410 MEDFileUtilities::AutoFid fid(MEDCoupling::OpenMEDFileForRead(fileName));
411 int mesh_dimension = -1;
412 std::vector<std::pair<MEDCoupling::TypeOfField,INTERP_KERNEL::NormalizedCellType>> tmp= { { field_type, type_geo_trio_to_type_medcoupling(mon_dom->type_elem()->que_suis_je(), mesh_dimension) } };
413 INTERP_KERNEL::AutoCppPtr<MEDCoupling::MEDFileEntities> entities(MEDCoupling::MEDFileEntities::BuildFrom(&tmp));
414 MCAuto<MEDCoupling::MEDFileAnyTypeField1TS> fieldFile = MEDCoupling::MEDFileAnyTypeField1TS::NewAdv(fid, fieldName, iteration, order, entities, filter);
415 MCAuto<MEDCoupling::MEDFileField1TS> ret(MEDCoupling::DynamicCast<MEDCoupling::MEDFileAnyTypeField1TS, MEDCoupling::MEDFileField1TS>(fieldFile));
416 if (!ret)
417 Process::exit("MED field: wrong type!");
418 MEDCoupling::DataArrayDouble *field_values = ret->getUndergroundDataArray();
419 std::copy(field_values->begin(),field_values->end(),
420 le_champ().valeurs().addr());
421#endif
422 }
423 else
424 {
425 MCAuto<MEDCouplingField> ffield;
426 bool has_field = ffield_!=nullptr;
427 if (!has_field) ffield = lire_champ(fileName, meshName, fieldName, iteration, order);
428 Cerr << " at time " << t << " ... " << finl;
429 MEDCouplingFieldDouble * field = dynamic_cast<MEDCouplingFieldDouble *>((MEDCouplingField *)(has_field?ffield_:ffield));
430 if (field == 0)
431 {
432 Cerr << "ERROR reading MED field! Not a MEDCouplingFieldDouble!!" << finl;
433 Process::exit(-1);
434 }
435 assert(field->getNumberOfTuplesExpected() == le_champ().valeurs().dimension(0));
436 assert((int) field->getNumberOfComponents() ==
437 (le_champ().valeurs().nb_dim() == 1 ? 1 : le_champ().valeurs().dimension(1)));
438 MEDCoupling::DataArrayDouble *field_values = field->getArray();
439 std::copy(field_values->begin(),field_values->end(),
440 le_champ().valeurs().addr());
441 }
442 }
443#endif // MEDCOUPLING_
444 // Update:
446 le_champ().Champ_Fonc_base::mettre_a_jour(t);
447#else // MED_
448 med_non_installe();
449#endif
450}
451
452int Champ_Fonc_MED::creer(const Nom& nom_fic, const Domaine& un_dom, const Motcle& localisation, ArrOfDouble& temps_sauv)
453{
454#ifdef MED_
455 nom_fichier_med_ = nom_fic;
456 mon_dom=un_dom;
457 const Nom& type_elem=un_dom.type_elem()->que_suis_je();
458 Nom type_champ;
460#ifdef MEDCOUPLING_
461 // MEDCoupling
462 int mesh_dimension = -1;
463 cell_type = type_geo_trio_to_type_medcoupling(type_elem, mesh_dimension);
464 if (localisation != Nom())
465 {
466 if (localisation == "som")
467 {
468 field_type = MEDCoupling::ON_NODES;
469 if ((cell_type == INTERP_KERNEL::NORM_QUAD4) || (cell_type == INTERP_KERNEL::NORM_HEXA8))
470 type_champ = "Champ_Fonc_Q1_MED";
471 else
472 type_champ = "Champ_Fonc_P1_MED";
473 }
474 else if (localisation == "elem")
475 {
476 field_type = MEDCoupling::ON_CELLS;
477 type_champ = "Champ_Fonc_P0_MED";
478 }
479 else
480 {
481 Cerr << localisation << " localization unknown." << finl;
482 exit();
483 }
484 }
485 std::string meshName = nom_maillage_ == "??" ? mon_dom->le_nom().getString() : nom_maillage_.getString();
486 std::string fileName = nom_fic.getString();
487 // Try to guess the field name in the MED file:
488 Noms fieldNamesGuess;
489 fieldNamesGuess.add((Motcle)nom_champ_dans_fichier_med_+"_"+mon_dom->le_nom());
490 if (localisation != Nom())
491 fieldNamesGuess.add((Motcle)nom_champ_dans_fichier_med_+"_"+localisation+"_"+mon_dom->le_nom());
492 fieldNamesGuess.add((Motcle)nom_champ_dans_fichier_med_);
493 if (!fieldNamesGuess.contient_(nom_champ_dans_fichier_med_))
494 fieldNamesGuess.add(nom_champ_dans_fichier_med_);
495 bool ok = false;
496 std::vector<std::string> fieldNames = GetAllFieldNamesOnMesh(fileName, meshName);
497 for (int i=0; i<fieldNamesGuess.size(); i++)
498 {
499 if (std::find(fieldNames.begin(), fieldNames.end(), fieldNamesGuess[i].getString()) != fieldNames.end())
500 {
501 nom_champ_dans_fichier_med_ = fieldNamesGuess[i];
502 ok = true;
503 break;
504 }
505 }
506 if (!ok)
507 {
508 Cerr << "Unable to find into file '" << fileName << "' a field named like :" << finl;
509 Cerr << " " << fieldNamesGuess << finl;
510 Cerr << "supported by mesh '" << meshName << "'" << finl;
511 Cerr << finl;
512 Cerr << "This file contains the field(s) named:" << finl;
513 for (unsigned i=0; i<fieldNames.size(); i++)
514 Cerr << fieldNames[i] << finl;
516 }
517 else
518 Cerr << "Ok, we find into file " << fileName << " a field named " << nom_champ_dans_fichier_med_ << finl;
519
520 std::string fieldName = nom_champ_dans_fichier_med_.getString();
521 int nbcomp,size;
522 lire_donnees_champ(fileName,meshName,fieldName,temps_sauv,size,nbcomp,type_champ);
523#endif // MEDCOUPLING_
524 // Definition:
525 vrai_champ_.typer(type_champ);
526 fixer_nb_comp(nbcomp);
527 le_champ().fixer_nb_comp(nbcomp);
528 domainebidon_inst.associer_domaine(un_dom);
530 le_champ().fixer_nb_valeurs_nodales(type_champ == "Champ_Fonc_P0_MED" ? un_dom.nb_elem() : un_dom.nb_som());
531 // force a read on the next update
532 changer_temps(-1e3);
534 return size;
535#else // MED_
536 med_non_installe();
537 return 0;
538#endif
539}
540
541#ifdef MEDCOUPLING_
542// Fill the time steps of field fieldName from file fileName
543ArrOfDouble Champ_Fonc_MED::lire_temps_champ(const std::string& fileName, const std::string& fieldName)
544{
545 ArrOfDouble temps_sauv;
546 MCAuto<MEDFileFieldMultiTS> ft1(MEDFileFieldMultiTS::New(fileName, fieldName));
547 std::vector<double> tps;
548 time_steps_ = ft1->getTimeSteps(tps);
549 unsigned int nn = (unsigned)tps.size();
550 temps_sauv.resize_array(nn);
551 for (unsigned it = 0; it < nn; it++)
552 temps_sauv[it] = tps[it];
553 return temps_sauv;
554}
555
556// Read the last field in the file just to discover and store:
557// the times (temps_sauv)
558// its size (size)
559// the number of components (nbcomp)
560// the type (type_champ)
561void Champ_Fonc_MED::lire_donnees_champ(const std::string& fileName, const std::string& meshName, const std::string& fieldName,
562 ArrOfDouble& temps_sauv, int& size, int& nbcomp, Nom& type_champ)
563{
564 temps_sauv = lire_temps_champ(fileName, fieldName);
565 unsigned int nn = temps_sauv.size_array();
566 int last_iter = time_steps_[nn-1].first;
567 int last_order = time_steps_[nn-1].second;
568 // Only one MCAuto below to avoid double deletion:
569 if (is_parallel()) // don't read the whole file in parallel mode
570 {
571 MCAuto<MEDFileField1TS> field = MEDFileField1TS::New(fileName, fieldName, last_iter, last_order);
572 nbcomp = (int) field->getNumberOfComponents();
574 size = -1;
575 else
576 {
577 MCAuto<MEDFileMesh> mesh = MEDFileMesh::New(fileName, meshName, field->getMeshIteration(), field->getMeshOrder());
578 size = field_type == MEDCoupling::ON_NODES ? (int)mesh->getNumberOfNodes() : (int)mesh->getNumberOfCellsAtLevel(0);
579 }
580 }
581 else
582 {
583 ffield_ = lire_champ(fileName, meshName, fieldName, last_iter, last_order);
584 MEDCouplingFieldDouble * field = dynamic_cast<MEDCouplingFieldDouble *>((MEDCouplingField *)ffield_);
585 if (field == 0)
586 {
587 Cerr << "ERROR reading MED field! Not a MEDCouplingFieldDouble!!" << finl;
588 Process::exit(-1);
589 }
590 size = (int)field->getNumberOfTuplesExpected();
591 nbcomp = (int)field->getNumberOfComponents();
592 if (nn>1) ffield_ = nullptr; // Multiple fields: do not store the last one, the correct one will be re-read
593 }
594
595 if (field_type == MEDCoupling::ON_CELLS)
596 type_champ = "Champ_Fonc_P0_MED";
597 else if (field_type == MEDCoupling::ON_NODES)
598 type_champ = cell_type == INTERP_KERNEL::NORM_QUAD4 || cell_type == INTERP_KERNEL::NORM_HEXA8 ? "Champ_Fonc_Q1_MED" : "Champ_Fonc_P1_MED";
599}
600
601/**
602 * @brief Read a MED field from a MED file and return it as a MEDCoupling field.
603 *
604 * This method reads the field @p fieldName stored in the MED file @p fileName on the mesh
605 * named @p meshName for the given time step (@p iteration, @p order).
606 *
607 * @param[in] fileName Path to the MED file to read.
608 * @param[in] meshName Name of the mesh on which the field is defined (as stored in the MED file).
609 * @param[in] fieldName Name of the field to read.
610 * @param[in] iteration Time step / iteration index to read (MEDCoupling convention).
611 * @param[in] order Order within the iteration to read (MEDCoupling convention).
612 *
613 * @return A smart-pointer-like handle (MCAuto) to the read @c MEDCouplingField.
614 *
615 * @note If @p meshName matches domaine().le_nom(), the method calls domaine().build_mc_mesh()
616 * before checking whether the MED mesh is ready, enabling fast mode when possible.
617 */
618MCAuto<MEDCouplingField> Champ_Fonc_MED::lire_champ(const std::string& fileName, const std::string& meshName,
619 const std::string& fieldName, const int iteration, const int order)
620{
621 // Faster field reading without reading the mesh if the MED mesh is already available:
622 if (meshName == domaine().le_nom() && !domaine().is_mc_mesh_ready()) domaine().build_mc_mesh();
623 bool fast = domaine().is_mc_mesh_ready();
624 Cerr << "Reading" << (fast ? " (fast)" : "") << " the field " << fieldName << " on the " << meshName << " mesh into " << fileName << " file" << finl;
625 MCAuto<MEDCouplingField> ffield;
626 if (fast) // Faster field reading without reading the associated mesh
627 {
628 MCAuto<MEDFileField1TS> file = MEDFileField1TS::New(fileName, fieldName, iteration, order);
629 ffield = file->getFieldOnMeshAtLevel(field_type, domaine().get_mc_mesh(), 0);
630 }
631 else // ~Twice slower field reading including reading of the associated mesh
632 {
633 ffield = ReadField(field_type, fileName, meshName, 0, fieldName, iteration, order);
634 }
635
636 return ffield;
637}
638#endif // MEDCOUPLING_
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
class Champ_Fonc_MED Load a field from a MED file for a given time.
const Domaine & domaine() const override
std::vector< trustIdType > filter
virtual void lire(double tps, int given_iteration=-1)
MCAuto< MEDCouplingField > ffield_
ArrOfDouble temps_sauv_
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
int creer(const Nom &, const Domaine &dom, const Motcle &localisation, ArrOfDouble &temps_sauv)
void mettre_a_jour(double) override
Time update of the field.
Domaine_VF_inst domainebidon_inst
virtual const Champ_Fonc_base & le_champ() const
virtual void set_param(Param &param) const override
Nom nom_champ_dans_fichier_med_
class Champ_Fonc_base Base class of fields that are functions of a calculated quantity
void associer_domaine_dis_base(const Domaine_dis_base &) override
void mettre_a_jour(double temps) override
Time update of the field.
int fixer_nb_valeurs_nodales(int nb_noeuds) override
Sets the number of degrees of freedom per component.
virtual double changer_temps(const double t)
Sets the time at which the field is defined.
void corriger_unite_nom_compo()
This method will set the units and the name of components, it is not actually const!...
DoubleTab getBoundingBox() const
Definition Domaine.cpp:883
int_t nb_elem() const
Definition Domaine.h:131
void build_mc_mesh(bool virt=false) const
Build the MEDCoupling mesh corresponding to the TRUST mesh.
Definition Domaine.cpp:1325
bool is_mc_mesh_ready() const
Definition Domaine.h:355
int_t nb_som() const
Returns the number of vertices of the domain.
Definition Domaine.h:121
const Nom & le_nom() const override
Returns the name of the Objet_U. Virtual method to override: returns "neant" in this implementation.
virtual int ouvrir(const char *name, IOS_OPEN_MODE mode=ios::in)
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual void fixer_nb_comp(int i)
Sets the number of components of the field.
const Nom & le_nom() const override
Returns the name of the field.
void nommer(const Nom &) override
Gives a name to the field.
static int objet_existant(const Nom &)
Returns 1 if the object exists, 0 otherwise. See Interprete_bloc::objet_global_existant().
A character string (Nom) in uppercase.
Definition Motcle.h:26
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
const std::string & getString() const
Definition Nom.h:92
const Nom & le_nom() const override
Returns *this.
Definition Nom.cpp:555
An array of character strings (VECT(Nom)).
Definition Noms.h:26
int contient_(const char *const ch) const
Definition Noms.cpp:60
const Interprete & interprete() const
Definition Objet_U.cpp:211
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 Entree & readOn(Entree &)
Reads an Objet_U from an input stream. Virtual method to override.
Definition Objet_U.cpp:289
static double precision_geom
Definition Objet_U.h:81
static const Nom & nom_du_cas()
Returns a constant reference to the case name. This method is static.
Definition Objet_U.cpp:145
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void ajouter_flag(const char *keyword, const bool *value)
Register a boolean flag whose mere presence switches it to true.
Definition Param.cpp:474
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ OPTIONAL
Definition Param.h:115
@ REQUIRED
Definition Param.h:115
static trustIdType mppartial_sum(trustIdType i)
Computes the partial sum of x over processors 0 to me()-1 (returns 0 on processor 0).
Definition Process.cpp:403
static double mp_max(double)
Definition Process.cpp:379
static bool is_parallel()
Definition Process.cpp:108
static int nproc()
Returns the number of processors in the current group. See Comm_Group::nproc() and PE_Groups::current...
Definition Process.cpp:102
static int me()
Returns the rank of the local processor in the current communication group. See Comm_Group::rank() an...
Definition Process.cpp:122
static void exit(int exit_code=-1)
Exit routine for TRUST within a Kokkos region.
Definition Process.cpp:466
Base class for output streams.
Definition Sortie.h:52
Iterator_ end()
Definition TRUSTArray.h:112
_SIZE_ size_array() const
void resize_array(_SIZE_ new_size, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133