TrioCFD 1.9.9_beta
TrioCFD documentation
Loading...
Searching...
No Matches
Moyenne_volumique.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 <Moyenne_volumique.h>
17#include <communications.h>
18#include <Equation_base.h>
19#include <Postraitement.h>
20#include <Octree_Double.h>
21#include <Domaine_VF.h>
22#include <TRUST_Ref.h>
23#include <algorithm>
24#include <Param.h>
25
26Implemente_instanciable(Moyenne_volumique,"Moyenne_volumique",Interprete);
27// XD moyenne_volumique interprete moyenne_volumique BRACE This keyword should be used after Resoudre keyword. It
28// XD_CONT computes the convolution product of one or more fields with a given filtering function.
29
31{
32 return s << que_suis_je() << finl;
33}
34
35/*! @brief Reading of the filtering function.
36 *
37 * @brief Expected format:
38 * {
39 * type BOITE|CHAPEAU|QUADRA|GAUSSIENNE|PARSER
40 * demie-largeur L
41 * [ omega W ]
42 * [ expression FORMULE ]
43 * }
44 *
45 * @param is the input stream
46 * @return the modified input stream
47 */
49{
50 expression_parser_ = "??";
51 int type = -1;
52 Param param(que_suis_je());
53 param.ajouter("type", & type, Param::REQUIRED /* obligatoire */);
54 param.dictionnaire("BOITE", BOITE);
55 param.dictionnaire("CHAPEAU", CHAPEAU);
56 param.dictionnaire("GAUSSIENNE", GAUSSIENNE);
57 param.dictionnaire("QUADRA", QUADRA);
58 param.dictionnaire("PARSER", PARSER);
59 param.ajouter("demie-largeur", & box_size_, Param::REQUIRED /* obligatoire */);
60 param.ajouter("omega", & l_);
61 param.ajouter("expression", & expression_parser_);
62 param.lire_avec_accolades_depuis(is);
63 switch(type)
64 {
65 case BOITE:
66 type_ = BOITE;
67 l_ = box_size_;
68 break;
69 case CHAPEAU:
70 type_ = CHAPEAU;
71 l_ = box_size_;
72 break;
73 case GAUSSIENNE:
75 if (l_ < 0.)
76 {
77 Cerr << "Error : OMEGA must be set to >= 0" << finl;
78 barrier();
79 exit();
80 }
81 break;
82 case PARSER:
83 type_ = PARSER;
84 if (expression_parser_ == "??")
85 {
86 Cerr << "Error : EXPRESSION must be specified for the parser." << finl;
87 barrier();
88 exit();
89 }
90 {
91 std::string s(expression_parser_);
92 std::transform(s.begin(), s.end(), s.begin(), ::toupper);
93 parser_.setString(s);
95 parser_.addVar("x");
96 parser_.addVar("y");
97 if (Objet_U::dimension == 3)
98 parser_.addVar("z");
99 parser_.parseString();
100 }
101 break;
102 case QUADRA:
103 type_ = QUADRA;
104 l_ = box_size_;
105 Cerr << "l_ = " << l_ << "box_size_ = " << box_size_ << finl;
106 break;
107 default:
108 exit(); // Internal error!
109 }
110 // Slight enlargement so that the octree correctly finds elements exactly on the boundary.
112 return is;
113}
114inline double fonction_quadra(double x, double l_)
115{
116 assert(std::fabs(x) <= l_);
117 double ax = 1. - std::fabs(x) / l_;
118 ax = ax * ax;
119 if (std::fabs(x) < (l_/3.))
120 {
121 double bx = -3. / l_ * std::fabs(x) + 1.;
122 ax -= bx * bx / 3.; // signifie ax = ax - bx*bx/3
123 }
124 return ax * (27. / (16. * l_));
125}
126/*! @brief Evaluates the filter function at each coordinate in coords.
127 *
128 * @brief Method called from the Calcul_integrale_locale class.
129 * @param coords the array of coordinates at which to evaluate the filter
130 * @param result the output array of filter values
131 */
132void Moyenne_volumique::eval_filtre(const DoubleTab& coords, ArrOfDouble& result) const
133{
134 const int dim = Objet_U::dimension;
135 assert(dim == coords.dimension(1));
136 const int n = coords.dimension(0);
137 assert(result.size_array() == n);
138 switch(type_)
139 {
140 case PARSER:
141 {
142 for (int i = 0; i < n; i++)
143 {
144 for (int j = 0; j < dim; j++)
145 parser_.setVar(j, coords(i,j));
146 result[i] = parser_.eval();
147 }
148 break;
149 }
150 case BOITE:
151 {
152 double facteur = 0.;
153 if (dim == 2)
154 facteur = 1. / (l_ * l_ * 4.);
155 else
156 facteur = 1. / (l_ * l_ * l_ * 8.);
157
158 for (int i = 0; i < n; i++)
159 {
160 const double x = coords(i,0);
161 const double y = coords(i,1);
162 const double z = (dim==3) ? coords(i,2) : 0.;
163 double r = facteur;
164 if (x > l_ || x < -l_
165 || y > l_ || y < -l_
166 || z > l_ || z < -l_)
167 r = 0.;
168 result[i] = r;
169 }
170 break;
171 }
172 case CHAPEAU:
173 {
174 const double L2D = l_*l_*l_*l_;
175 const double L3D = L2D*l_*l_;
176 double facteur;
177 if (dim==3)
178 facteur = 1. / L3D;
179 else
180 facteur = 1. / (L2D * l_);
181 const int nbis = coords.dimension(0);
182 for (int i = 0; i < nbis; i++)
183 {
184 const double x = coords(i, 0);
185 const double y = coords(i, 1);
186 const double z = (dim == 3) ? coords(i, 2) : 0.;
187 double resu = 0.;
188 const double ax = std::fabs(x);
189 const double ay = std::fabs(y);
190 const double az = std::fabs(z);
191 if (ax <= l_ && ay <= l_ && az <= l_)
192 resu = (l_-ax) * (l_-ay) * (l_-az) * facteur;
193 result[i] = resu;
194 }
195 break;
196 }
197 case GAUSSIENNE:
198 {
199 double facteur1 = - 0.5 / (l_ * l_);
200 double facteur2 = 1. / (l_ * sqrt(2 * M_PI));
201 if (dim == 2)
202 facteur2 = facteur2 * facteur2;
203 else
204 facteur2 = facteur2 * facteur2 * facteur2;
205 for (int i = 0; i < n; i++)
206 {
207 const double x = coords(i, 0);
208 const double y = coords(i, 1);
209 const double z = (dim == 3) ? coords(i, 2) : 0.;
210 const double k = (x*x + y*y + z*z) * facteur1;
211 result[i] = exp(k) * facteur2;
212 }
213 break;
214 }
215 case QUADRA:
216 {
217 for (int i = 0; i < n; i++)
218 {
219 const double x = coords(i, 0);
220 const double y = coords(i, 1);
221 const double z = (dim == 3) ? coords(i, 2) : 0.;
222 double resu = 0;
223 if (std::fabs(x) < l_ && std::fabs(y) < l_ && std::fabs(z) < l_)
224 {
225 resu = fonction_quadra(x,l_) * fonction_quadra(y,l_);
226 if (dim == 3)
227 resu *= fonction_quadra(z,l_);
228 }
229 result[i] = resu;
230 }
231 break;
232 }
233 default:
234 {
235 Cerr << "Error in Moyenne_volumique::eval() : filter function is not initialized." << finl;
236 exit();
237 }
238 }
239}
240
241/*! @brief Searches for the field named "nom_champ" in the problem named "nom_pb" among the interpreter objects.
242 *
243 * @brief Method called by traiter_champs().
244 * @param nom_pb the name of the problem
245 * @param nom_champ the name of the field to retrieve
246 * @param ref_champ reference to the field, set on output
247 * @return 1 on success
248 */
250 const Nom& nom_champ,
251 OBS_PTR(Champ_base) & ref_champ)
252{
253 Probleme_base& pb = ref_cast(Probleme_base, objet(nom_pb));
254 // Le champ est-il defini dans les postraitements (statistiques) ?
255 const int nb_post = pb.postraitements().size();
256 Motcle mc_nom_champ(nom_champ);
257 for (int i_post = 0; i_post < nb_post; i_post++)
258 {
259 if (sub_type(Postraitement_base, pb.postraitements()[i_post].valeur()))
260 {
261 Postraitement& post = ref_cast(Postraitement, pb.postraitements()[i_post].valeur());
263 const int nstat = stats.size();
264 for (int i_stat = 0; i_stat < nstat; i_stat++)
265 {
266 Motcle tmp(stats[i_stat]->le_nom() );
267
268 if (tmp == mc_nom_champ)
269 {
270 Operateur_Statistique_tps_base& stat = stats[i_stat].valeur();
271 ref_cast_non_const(DoubleTab, stat.integrale().le_champ_calcule().valeurs()) = stat.calculer_valeurs();
272 ref_champ = stat.integrale().le_champ_calcule();
273 return 1;
274 }
275 }
276 }
277 }
278
279 ref_champ = pb.get_champ(nom_champ);
280 return 1;
281}
282
283/*! @brief Helper function that performs the convolution calculations and writes the result to a lata file for all fields of a given type listed in noms_champs.
284 *
285 * @brief Method called by interpreter().
286 * type_champ=0 => process element fields
287 * type_champ=1 => process face fields
288 * @param noms_champs list of field names to process
289 * @param nom_pb name of the problem
290 * @param nom_dom name of the destination domain
291 * @param coords coordinates at which to evaluate the convolution
292 * @param post the post-processing format object used for writing
293 * @param temps current time
294 * @param localisation field localisation (ELEM or SOM)
295 */
297 const Nom& nom_pb, const Nom& nom_dom,
298 const DoubleTab& coords,
299 Format_Post_base& post,
300 double temps,
301 const Motcle& localisation)
302{
303 const Domaine& dom_post = ref_cast(Domaine, objet(nom_dom));
304 const int nb_champs = noms_champs.size();
305 if (nb_champs == 0)
306 return;
307
308 OBS_PTR(Champ_base) ref_champ;
309 OBS_PTR(Domaine_VF) ref_domaine_vf;
310 int i_champ;
311 // ************************************
312 // Compute the total number of components and ref_domaine_vf
313 int nb_compo_tot = 0;
314 for (i_champ = 0; i_champ < nb_champs; i_champ++)
315 {
316 get_champ(nom_pb, noms_champs[i_champ], ref_champ);
317 const Champ_base& champ = ref_champ.valeur();
318 const Domaine_VF& zvf = ref_cast(Domaine_VF, champ.domaine_dis_base());
319 if (i_champ == 0)
320 {
321 ref_domaine_vf = zvf;
322 }
323 else
324 {
325 if (& (ref_domaine_vf.valeur()) != & zvf)
326 {
327 Cerr << "Error in Moyenne_volumique::traiter_champs all the fields must be discretized on the same Domaine." << finl;
328 barrier();
329 exit();
330 }
331 }
332 const int nb_compo = champ.nb_comp();
333 nb_compo_tot += nb_compo;
334 }
335
336 const Domaine_VF& domaine_source = ref_domaine_vf.valeur();
337
338 // ************************************
339 // Build a large array containing all the values to process plus the porosity
340 DoubleTab valeurs_src;
341 const int nb_lignes = domaine_source.nb_elem();
342 valeurs_src.resize(nb_lignes, nb_compo_tot + 1);
343 int count = 0;
344 {
345 DoubleTab tmp_val;
346 IntVect liste_elems(nb_lignes);
347 for (int i = 0; i < nb_lignes; i++)
348 liste_elems[i] = i;
349 const DoubleTab& xp = domaine_source.xp();
350 for (i_champ = 0; i_champ < nb_champs; i_champ++)
351 {
352 get_champ(nom_pb, noms_champs[i_champ], ref_champ);
353 const Champ_base& champ = ref_champ.valeur();
354 const int nb_compo = champ.nb_comp();
355 tmp_val.reset();
356 tmp_val.resize(nb_lignes, nb_compo);
357 champ.valeur_aux_elems(xp, liste_elems, tmp_val);
358
359 for (int i = 0; i < nb_lignes; i++)
360 for (int j = 0; j < nb_compo; j++)
361 valeurs_src(i, count+j) = tmp_val(i, j);
362 count += nb_compo;
363
364 Cout << "Field name = " << ref_champ->le_nom()
365 << " Field type = " << ref_champ->que_suis_je() << finl;
366 }
367 }
368 // et une colonne de 1:
369 for (int i = 0; i < nb_lignes; i++)
370 valeurs_src(i, count) = 1.;
371
372 // Tableau de resultats:
373 const int nb_coords = coords.dimension(0);
374 DoubleTab resu(nb_coords, nb_compo_tot + 1);
375
376 // ************************************
377 // Compute all convolution products
378
379 calculer_convolution_champ_elem(domaine_source,
380 valeurs_src,
381 coords,
382 resu);
383 Noms nom_dir;
384 nom_dir.add("_X");
385 nom_dir.add("_Y");
386 nom_dir.add("_Z");
387 count = 0;
388 for (i_champ = 0; i_champ < nb_champs; i_champ++)
389 {
390 get_champ(nom_pb, noms_champs[i_champ], ref_champ);
391 const Champ_base& champ = ref_champ.valeur();
392 const int nb_compo = champ.nb_comp();
393 DoubleTab extrait(nb_coords, nb_compo);
394 for (int i = 0; i < nb_coords; i++)
395 for (int j = 0; j < nb_compo; j++)
396 extrait(i, j) = resu(i, count + j);
397
398 Cout << "Post writting " << champ.le_nom() << finl;
399 Nom nature("scalar");
400 if (champ.nature_du_champ()==vectoriel) nature="vector";
401 post.ecrire_champ(dom_post,
402 champ.unites(),
403 champ.noms_compo(),
404 -1 /* ecrire toutes les composantes */, temps,
405 noms_champs[i_champ], nom_dom, localisation,nature, extrait);
406
407 count += nb_compo;
408 }
409 // Derniere colonne (porosite)
410 const int nb_compo = 1;
411 DoubleTab extrait(nb_coords, nb_compo);
412 for (int i = 0; i < nb_coords; i++)
413 for (int j = 0; j < nb_compo; j++)
414 extrait(i, j) = resu(i, count + j);
415
416 Noms noms_compo;
417 Noms unites;
418 Nom nom_moyenne;
419 unites.add("m3");
420 noms_compo.add("porosite");
421 nom_moyenne = "porosite";
422 Cout << "Porosity post writing" << finl;
423
424 post.ecrire_champ(dom_post, unites, noms_compo, -1 /* ecrire toutes les composantes */,
425 temps,
426 nom_moyenne, nom_dom, localisation, "scalar",extrait);
427}
428
429/*! @brief Reads the parameters from the data set.
430 *
431 * @brief Expected format: Moyenne_volumique {
432 * nom_pb NOM_DU_PROBLEME (where to look for the source fields)
433 * nom_domaine DOMAINE_CIBLE (the convolution is evaluated at the elements of this domain)
434 * noms_champs N CHAMP1 CHAMP2 ... (names of the fields to filter in the problem)
435 * [ nom_fichier_post NOM_SANS_EXTENSION ] (either nom_fichier and format_post are given,
436 * or fichier_post is given)
437 * [ format_post lata|lml|med|... ] (default: lata)
438 * [ fichier_post Format_Post_XXX { ... } ] (read via readOn of Format_Post_XXX)
439 * fonction_filtre ... (format: see Moyenne_volumique::readOn() )
440 * [ localisation ELEM|SOM ]
441 * }
442 *
443 * @param is the input stream
444 * @return the modified input stream
445 */
447{
448 Cerr << "Starting of Moyenne_volumique::interpreter" << finl;
449 Nom nom_pb, nom_dom;
450 Motcles noms_champs;
451 Param param(que_suis_je() + Nom("::interpreter()"));
452 const int id_elem = 0;
453 const int id_som = 1;
454 int localisation = id_elem; // default
455 Motcle format_post("lata_v1");
456 Nom nom_fichier_post;
457 OWN_PTR(Format_Post_base) fichier_post;
458 param.ajouter("nom_pb", & nom_pb, Param::REQUIRED); // XD_ADD_P ref_Pb_base
459 // XD_CONT name of the problem where the source fields will be searched.
460 param.ajouter("nom_domaine", & nom_dom, Param::REQUIRED); // XD_ADD_P ref_domaine
461 // XD_CONT name of the destination domain (for example, it can be a coarser mesh, but for optimal performance in
462 // XD_CONT parallel, the domain should be split with the same algorithm as the computation mesh, eg, same tranche
463 // XD_CONT parameters for example)
464 param.ajouter("noms_champs", & noms_champs, Param::REQUIRED); // XD_ADD_P listchaine
465 // XD_CONT name of the source fields (these fields must be accessible from the postraitement) N source_field1
466 // XD_CONT source_field2 ... source_fieldN
467 param.ajouter("fichier_post", & fichier_post);
468 param.ajouter("format_post", & format_post); // XD_ADD_P chaine
469 // XD_CONT gives the fileformat for the result (by default : lata)
470 param.ajouter("nom_fichier_post", & nom_fichier_post); // XD_ADD_P chaine
471 // XD_CONT indicates the filename where the result is written
472 // The Moyenne_volumique object is an interpreter, but it is also an object
473 // whose only property is the filter function to use. Trick:
474 // call the class readOn to read the filter function.
475 param.ajouter("fonction_filtre", this, Param::REQUIRED); // XD_ADD_P bloc_lecture
476 // XD_CONT to specify the given filter NL2 Fonction_filtre {NL2 type filter_typeNL2 demie-largeur lNL2 [ omega w ] NL2
477 // XD_CONT [ expression string ]NL2 } NL2 NL2 type filter_type : This parameter specifies the filtering function.
478 // XD_CONT Valid filter_type are:NL2 Boite is a box filter, $f(x,y,z)=(abs(x)<l)*(abs(y) <l)*(abs(z) <l) / (8 l^3)$NL2
479 // XD_CONT Chapeau is a hat filter (product of hat filters in each direction) centered on the origin, the half-width
480 // XD_CONT of the filter being l and its integral being 1.NL2 Quadra is a 2nd order filter.NL2 Gaussienne is a
481 // XD_CONT normalized gaussian filter of standard deviation sigma in each direction (all field elements outside a
482 // XD_CONT cubic box defined by clipping_half_width are ignored, hence, taking clipping_half_width=2.5*sigma yields an
483 // XD_CONT integral of 0.99 for a uniform unity field).NL2 Parser allows a user defined function of the x,y,z
484 // XD_CONT variables. All elements outside a cubic box defined by clipping_half_width are ignored. The parser is much
485 // XD_CONT slower than the equivalent c++ coded function...NL2 NL2 demie-largeur l : This parameter specifies the half
486 // XD_CONT width of the filterNL2 [ omega w ] : This parameter must be given for the gaussienne filter. It defines the
487 // XD_CONT standard deviation of the gaussian filter.NL2 [ expression string] : This parameter must be given for the
488 // XD_CONT parser filter type. This expression will be interpreted by the math parser with the predefined variables x,
489 // XD_CONT y and z.
490 param.ajouter("localisation", & localisation); // XD_ADD_P chaine(into=["elem","som"])
491 // XD_CONT indicates where the convolution product should be computed: either on the elements or on the nodes of the
492 // XD_CONT destination domain.
493 param.dictionnaire("ELEM", id_elem);
494 param.dictionnaire("SOM", id_som);
496
497 // retrieve the domain
498 const Domaine& dom = ref_cast(Domaine, objet(nom_dom));
499 if (noms_champs.size() == 0)
500 {
501 Cerr << "Moyenne_volumique : no field to treat" << finl;
502 return is;
503 }
504 Cerr << "Writing of the post-processing domain : " << nom_dom << finl;
505 OBS_PTR(Champ_base) ref_champ;
506 get_champ(nom_pb, noms_champs[0], ref_champ);
507 const double temps = ref_champ->temps();
508 if (!fichier_post)
509 {
510 if (nom_fichier_post == "??")
511 {
512 Cerr << "Error in Moyenne_volumique::interpreter:\n"
513 << " missing NOM_FICHIER_POST or FICHIER_POST keyword" << finl;
514 barrier();
515 exit();
516 }
517 if (format_post == "lata_v2")
518 format_post = "lata";
519 // Trick to allow the non-regression test case to run in both sequential and parallel:
520 // (the output file name must match the case name)
521 if (nom_fichier_post == "NOM_DU_CAS")
522 {
523 Cerr << "Post filename = NOM_DU_CAS => using " << nom_du_cas() << " instead" << finl;
524 nom_fichier_post = nom_du_cas();
525 }
526 fichier_post.typer(Motcle("FORMAT_POST_") + format_post);
527 fichier_post->initialize(nom_fichier_post, 1 /* binaire */, "SIMPLE");
528 }
529 else
530 {
531 if (nom_fichier_post != "??")
532 {
533 Cerr << "Error in Moyenne_volumique::interpreter:\n"
534 << " you cannot give NOM_FICHIER_POST and FICHIER_POST. Choose one" << finl;
535 barrier();
536 exit();
537 }
538 }
539 Format_Post_base& post = fichier_post.valeur();
540 post.ecrire_entete(temps, 0 /*reprise*/, 1 /* premier post */);
541 post.ecrire_domaine(dom, 1 /* premier_post */);
542 post.ecrire_temps(temps);
543
544 // Coordinates of the element centres of the destination domain
545 DoubleTab coords;
546 if (localisation == id_elem)
547 {
548 dom.calculer_centres_gravite(coords);
549 // The array also contains virtual elements but without a virtual space. Beware.
550 coords.resize(dom.nb_elem(), coords.dimension(1));
551 }
552 else
553 {
554 coords = dom.les_sommets();
555 }
556
557 Motcle loc("ELEM");
558 if (localisation == id_som)
559 loc = "SOM";
560 traiter_champs(noms_champs,
561 nom_pb,
562 nom_dom,
563 coords,
564 post,
565 temps,
566 loc);
567 int fin=1;
568 post.finir(fin);
569 return is;
570}
571
572/*! @brief Helper class used internally by calculer_convolution().
573 *
574 */
576{
577public:
578 Calcul_integrale_locale(const Domaine_VF& domaine_source,
579 const Moyenne_volumique& filter,
580 const DoubleTab& champ_source);
581 void calculer(double x, double y, double z, ArrOfDouble& resu);
582
583protected:
585 Octree_Double octree_;
587 const DoubleTab& champ_source_;
588 // Temporary arrays used in calculer():
589 ArrOfInt liste_elems_;
590 DoubleTab filter_coords_;
591 ArrOfDouble filter_results_;
593};
594
595/*! @brief Constructor of the helper class.
596 *
597 * @brief See Moyenne_volumique::calculer_convolution().
598 * @param domaine_source the source discretized domain
599 * @param filter the volumetric average filter object
600 * @param champ_source the source field values array
601 */
603 const Moyenne_volumique& filter,
604 const DoubleTab& champ_source) :
605 domaine_source_(domaine_source),
606 filter_(filter),
607 champ_source_(champ_source)
608{
609
610
611
612 // Build an octree containing the element centres.
613 // The array is copied because it will be resized:
614 DoubleTab coords = domaine_source.xp();
615 nb_items_reels_ = domaine_source.nb_elem();
616 // The xp array is dimensioned with dimension(0)=nb_elem_tot; resize it to nb_elem.
617 coords.resize(nb_items_reels_, coords.dimension(1));
618 if (champ_source.dimension(0) != nb_items_reels_)
619 {
620 Cerr << "Error in Calcul_integrale_locale::Calcul_integrale_locale() :\n"
621 << " The source field is not discretized at the elements" << finl;
622 Process::barrier();
623 Process::exit();
624 }
625 octree_.build_nodes(coords, 0 /* no virtual items */);
626}
627
628/*! @brief Evaluates the convolution product "filter_ * champ_source_" at point x,y,z and stores the result in resu.
629 *
630 * @brief The elements to use are determined based on the filter size using an octree.
631 * The source field is assumed to be element-centred.
632 * Method called by Moyenne_volumique::calculer_convolution().
633 * @param x x-coordinate of the evaluation point
634 * @param y y-coordinate of the evaluation point
635 * @param z z-coordinate of the evaluation point
636 * @param resu output array receiving the convolution result
637 */
638void Calcul_integrale_locale::calculer(const double x, const double y, const double z,
639 ArrOfDouble& resu)
640{
641 const double box_size = filter_.box_size();
642 octree_.search_elements_box(x - box_size, y - box_size, z - box_size,
643 x + box_size, y + box_size, z + box_size,
645
646 const DoubleTab& coord_items = domaine_source_.xp();
647
648 const int nb_items = liste_elems_.size_array();
649 const int dim = Objet_U::dimension;
650 filter_coords_.resize(nb_items, dim);
651 for (int i = 0; i < nb_items; i++)
652 {
653 const int item = liste_elems_[i];
654 assert(item < nb_items_reels_);
655 filter_coords_(i, 0) = coord_items(item, 0) - x;
656 filter_coords_(i, 1) = coord_items(item, 1) - y;
657 if (dim == 3)
658 filter_coords_(i, 2) = coord_items(item, 2) - z;
659 }
660 filter_results_.resize_array(nb_items);
662
663 const DoubleVect& volumes = domaine_source_.volumes();
664 const int nb_comp = champ_source_.dimension(1);
665 resu = 0.;
666 for (int i = 0; i < nb_items; i++)
667 {
668 const int item = liste_elems_[i];
669 const double valeur_filtre = filter_results_[i];
670 const double volume = volumes(item);
671 const double facteur = valeur_filtre * volume;
672 for (int j = 0; j < nb_comp; j++)
673 {
674 // The integral is coarsely discretized as the product of the
675 // values at the element centre times the element volume:
676 const double valeur_champ = champ_source_(item, j);
677 resu[j] += valeur_champ * facteur;
678 }
679 }
680}
681
682/*! @brief General method to compute a convolution from a field defined at elements or faces.
683 *
684 * @brief Method called by calculer_convolution_champ_elem() and calculer_convolution_champ_face().
685 * @param domaine_source the source discretized domain
686 * @param champ_source the source field values array
687 * @param coords_to_compute coordinates at which to evaluate the convolution
688 * @param resu output array of convolution results
689 */
691 const DoubleTab& champ_source,
692 const DoubleTab& coords_to_compute,
693 DoubleTab& resu) const
694{
695 assert(resu.dimension(0) == coords_to_compute.dimension(0));
696 const int dim = Objet_U::dimension;
697 const int nbproc = Process::nproc();
698 const int nb_coords_to_compute = coords_to_compute.dimension(0);
699 const int nb_coords_max = mp_max(nb_coords_to_compute);
700
701 int nb_comp;
702 nb_comp = champ_source.line_size();
703 assert(resu.line_size() == nb_comp);
704
705 DoubleTab coords(nbproc, 3);
706 ArrOfInt flag(nbproc);
707 ArrOfDouble resu_partiel(nb_comp);
708 DoubleTab resu_partiels(nbproc, nb_comp);
709
710 Calcul_integrale_locale integrale_locale(domaine_source,
711 *this,
712 champ_source);
713
714 // Loop over local coordinates x for which we want to compute the integral I(x).
715 // If x is near the boundary, the filter function support covers neighbouring processors
716 // whose contributions must be included. For each coordinate, all other processors are asked
717 // to compute their contribution. We therefore loop over the maximum number of coordinates
718 // to synchronize all processes:
719 int i, j;
720 for (int i_coord = 0; i_coord < nb_coords_max; i_coord++)
721 {
722 // Each processor sends the coordinate to compute to all other processors:
723 if (i_coord < nb_coords_to_compute)
724 {
725 for (j = 0; j < dim; j++)
726 {
727 double x = coords_to_compute(i_coord, j);
728 for (i = 0; i < nbproc; i++)
729 coords(i, j) = x;
730 }
731 flag = 1;
732 }
733 else
734 {
735 flag = 0;
736 }
737 envoyer_all_to_all(coords, coords);
738 envoyer_all_to_all(flag, flag);
739 // coord(pe, i) holds the coordinates requested by each processor, and
740 // flag[pe] indicates whether that processor has requested a coordinate or has exhausted
741 // its coords_to_compute list.
742 // We now compute the local processor's contribution to the integrals I(x) for these
743 // coordinates. In general, the processor that owns the coordinate does most of the work
744 // for it and almost nothing for other coordinates (if the coordinate is far from the
745 // local domain, the octree quickly returns an empty list).
746 // The workload is therefore approximately balanced across processors.
747 for (i = 0; i < nbproc; i++)
748 {
749 if (flag[i])
750 {
751 integrale_locale.calculer(coords(i, 0), coords(i, 1), coords(i, 2), resu_partiel);
752 for (j = 0; j < nb_comp; j++)
753 resu_partiels(i, j) = resu_partiel[j];
754 }
755 }
756 // Send back to each processor the local processor's contribution for the coordinate it requested:
757 envoyer_all_to_all(resu_partiels, resu_partiels);
758 // The result is the sum of contributions from all processors:
759 if (i_coord < nb_coords_to_compute)
760 {
761 for (j = 0; j < nb_comp; j++)
762 {
763 double x = 0.;
764 for (i = 0; i < nbproc; i++)
765 x += resu_partiels(i, j);
766 resu(i_coord, j) = x;
767 }
768 }
769 }
770}
771
772/*! @brief Computes the convolution product between the filter function and the field "champ_source", which must be discretized at the elements of "domaine_source".
773 *
774 * @brief The resu array has the same number of columns as "champ_source" and the same number
775 * of rows as coords_to_compute.
776 * The filter function is assumed to have support contained in a cube of half-side box_size
777 * centred on the origin (contributions of elements outside this cube are ignored).
778 * @param domaine_source the source discretized domain
779 * @param champ_source the source field values array
780 * @param coords_to_compute coordinates at which to evaluate the convolution
781 * @param resu output array of convolution results
782 */
784 const DoubleTab& champ_source,
785 const DoubleTab& coords_to_compute,
786 DoubleTab& resu) const
787{
788 assert(champ_source.dimension(0) == domaine_source.domaine().nb_elem());
789 calculer_convolution(domaine_source, champ_source,
790 coords_to_compute, resu);
791}
792
793/*! @brief Same as calculer_convolution_champ_elem but for a VDF face field.
794 *
795 * @brief The source field is assumed to be a vector field containing, for each face,
796 * the normal component of the field at that face.
797 * For each column of the champ_source array, "dimension" columns of resu are filled:
798 * the first using only faces with X-normal, the second with Y-normal faces, etc.
799 * @param domaine_source the source discretized domain
800 * @param champ_source the source face field values array
801 * @param coords_to_compute coordinates at which to evaluate the convolution
802 * @param resu output array of convolution results
803 */
805 const DoubleTab& champ_source,
806 const DoubleTab& coords_to_compute,
807 DoubleTab& resu) const
808{
809 Cerr << " Moyenne_volumique::calculer_convolution_champ_face is not coded" << finl;
810 exit();
811}
Helper class used internally by calculer_convolution().
const DoubleTab & champ_source_
void calculer(double x, double y, double z, ArrOfDouble &resu)
Evaluates the convolution product "filter_ * champ_source_" at point x,y,z and stores the result in r...
const Moyenne_volumique & filter_
Calcul_integrale_locale(const Domaine_VF &domaine_source, const Moyenne_volumique &filter, const DoubleTab &champ_source)
Constructor of the helper class.
const Domaine_VF & domaine_source_
DoubleTab & valeurs() override
Overrides Champ_base::valeurs() Returns the array of values.
class Champ_base This class is the base of the fields hierarchy.
Definition Champ_base.h:43
void calculer_centres_gravite(DoubleTab_t &xp) const
Calculates the centers of gravity of the domain elements.
Definition Domaine.h:503
DoubleTab_t & les_sommets()
Definition Domaine.h:113
int_t nb_elem() const
Definition Domaine.h:131
class Domaine_VF
Definition Domaine_VF.h:44
double xp(int num_elem, int k) const
Definition Domaine_VF.h:77
const Domaine & domaine() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
virtual int nb_comp() const
Definition Field_base.h:56
Base class for post-processing output formats for fields (lata, med, cgns, lml, single_lata).
virtual int finir(const int est_le_dernier_post)
virtual int ecrire_champ(const Domaine &domaine, const Noms &unite_, const Noms &noms_compo, int ncomp, double temps_, const Nom &id_du_champ, const Nom &id_du_domaine, const Nom &localisation, const Nom &nature, const DoubleTab &data)
Writing a field to the post-processing file.
virtual int ecrire_temps(const double temps)
Starts writing a time step.
virtual int ecrire_entete(const double temps_courant, const int reprise, const int est_le_premier_post)
virtual int ecrire_domaine(const Domaine &domaine, const int est_le_premier_post)
Writing a mesh.
const Champ_Fonc_base & le_champ_calcule() const
Base class for "interpreter" objects.
Definition Interprete.h:38
static Objet_U & objet(const Nom &)
See Interprete_bloc::objet_global(). BM: the Interprete class is not the best place for this.
A character string (Nom) in uppercase.
Definition Motcle.h:26
An array of Motcle objects.
Definition Motcle.h:63
This interpreter computes and stores in a lata file the convolution product.
virtual void calculer_convolution_champ_elem(const Domaine_VF &domaine_source, const DoubleTab &champ_source, const DoubleTab &coords_to_compute, DoubleTab &resu) const
Computes the convolution product between the filter function and the field "champ_source",...
virtual void calculer_convolution_champ_face(const Domaine_VF &domaine_source, const DoubleTab &champ_source, const DoubleTab &coords_to_compute, DoubleTab &resu) const
Same as calculer_convolution_champ_elem but for a VDF face field.
int get_champ(const Nom &nom_pb, const Nom &nom_champ, OBS_PTR(Champ_base) &ref_champ)
Searches for the field named "nom_champ" in the problem named "nom_pb" among the interpreter objects.
virtual void calculer_convolution(const Domaine_VF &domaine_source, const DoubleTab &champ_source, const DoubleTab &coords_to_compute, DoubleTab &resu) const
General method to compute a convolution from a field defined at elements or faces.
void traiter_champs(const Motcles &noms_champs, const Nom &nom_pb, const Nom &nom_dom, const DoubleTab &coords, Format_Post_base &post, double temps, const Motcle &localisation)
Helper function that performs the convolution calculations and writes the result to a lata file for a...
Entree & interpreter(Entree &) override
Reads the parameters from the data set.
virtual void eval_filtre(const DoubleTab &coords, ArrOfDouble &result) const
Evaluates the filter function at each coordinate in coords.
class Nom: a character string for naming TRUST objects.
Definition Nom.h:31
An array of character strings (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:71
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 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
virtual Sortie & printOn(Sortie &) const
Writes the object to an output stream. Virtual method to override.
Definition Objet_U.cpp:278
class Operateur_Statistique_tps_base
virtual const Integrale_tps_Champ & integrale() const =0
virtual DoubleTab calculer_valeurs() const =0
class Operateurs_Statistique_tps
Helper class to factorize the readOn method of Objet_U classes.
Definition Param.h:112
void dictionnaire(const char *option_name, int value)
Add an (option name, integer value) entry to the dictionary attached to a previously registered integ...
Definition Param.cpp:293
void ajouter(const char *keyword, const int *value, Param::Nature nat=Param::OPTIONAL)
Register an integer parameter.
Definition Param.cpp:364
@ REQUIRED
Definition Param.h:115
int lire_avec_accolades_depuis(Entree &is)
Parse the parameter block { ... } from is.
Definition Param.cpp:32
Base class for all post-processing objects.
class Postraitement. The class holds -a list of generic fields champs_post_complet_ containing
Operateurs_Statistique_tps & les_statistiques()
class Probleme_base It is a Probleme_U that is not a coupling.
const Champ_base & get_champ(const Motcle &nom) const override
Postraitements & postraitements()
static double mp_max(double)
Definition Process.cpp:379
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 void barrier()
Synchronizes all processors in the current group (waits until all processors have reached the barrier...
Definition Process.cpp:133
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
_SIZE_ size_array() const
void reset() override
Definition TRUSTTab.tpp:362
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
int line_size() const
Definition TRUSTVect.tpp:67