TrioCFD 1.9.8
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 lecture de la fonction de filtrage.
36 *
37 * {
38 * type BOITE|CHAPEAU|QUADRA|GAUSSIENNE|PARSER
39 * demie-largeur L
40 * [ omega W ]
41 * [ expression FORMULE ]
42 * }
43 *
44 */
46{
47 expression_parser_ = "??";
48 int type = -1;
49 Param param(que_suis_je());
50 param.ajouter("type", & type, Param::REQUIRED /* obligatoire */);
51 param.dictionnaire("BOITE", BOITE);
52 param.dictionnaire("CHAPEAU", CHAPEAU);
53 param.dictionnaire("GAUSSIENNE", GAUSSIENNE);
54 param.dictionnaire("QUADRA", QUADRA);
55 param.dictionnaire("PARSER", PARSER);
56 param.ajouter("demie-largeur", & box_size_, Param::REQUIRED /* obligatoire */);
57 param.ajouter("omega", & l_);
58 param.ajouter("expression", & expression_parser_);
59 param.lire_avec_accolades_depuis(is);
60 switch(type)
61 {
62 case BOITE:
63 type_ = BOITE;
64 l_ = box_size_;
65 break;
66 case CHAPEAU:
67 type_ = CHAPEAU;
68 l_ = box_size_;
69 break;
70 case GAUSSIENNE:
72 if (l_ < 0.)
73 {
74 Cerr << "Error : OMEGA must be set to >= 0" << finl;
75 barrier();
76 exit();
77 }
78 break;
79 case PARSER:
80 type_ = PARSER;
81 if (expression_parser_ == "??")
82 {
83 Cerr << "Error : EXPRESSION must be specified for the parser." << finl;
84 barrier();
85 exit();
86 }
87 {
88 std::string s(expression_parser_);
89 std::transform(s.begin(), s.end(), s.begin(), ::toupper);
90 parser_.setString(s);
92 parser_.addVar("x");
93 parser_.addVar("y");
94 if (Objet_U::dimension == 3)
95 parser_.addVar("z");
96 parser_.parseString();
97 }
98 break;
99 case QUADRA:
100 type_ = QUADRA;
101 l_ = box_size_;
102 Cerr << "l_ = " << l_ << "box_size_ = " << box_size_ << finl;
103 break;
104 default:
105 exit(); // Erreur interne !
106 }
107 // Pour que l'octree trouve bien les elements qui sont pile-poil a la limite.
109 return is;
110}
111inline double fonction_quadra(double x, double l_)
112{
113 assert(std::fabs(x) <= l_);
114 double ax = 1. - std::fabs(x) / l_;
115 ax = ax * ax;
116 if (std::fabs(x) < (l_/3.))
117 {
118 double bx = -3. / l_ * std::fabs(x) + 1.;
119 ax -= bx * bx / 3.; // signifie ax = ax - bx*bx/3
120 }
121 return ax * (27. / (16. * l_));
122}
123/*! @brief Evalue la fonction filtre en chaque coordonnee coord Methode appelee dans la classe Calcul_integrale_locale
124 *
125 */
126void Moyenne_volumique::eval_filtre(const DoubleTab& coords, ArrOfDouble& result) const
127{
128 const int dim = Objet_U::dimension;
129 assert(dim == coords.dimension(1));
130 const int n = coords.dimension(0);
131 assert(result.size_array() == n);
132 switch(type_)
133 {
134 case PARSER:
135 {
136 for (int i = 0; i < n; i++)
137 {
138 for (int j = 0; j < dim; j++)
139 parser_.setVar(j, coords(i,j));
140 result[i] = parser_.eval();
141 }
142 break;
143 }
144 case BOITE:
145 {
146 double facteur = 0.;
147 if (dim == 2)
148 facteur = 1. / (l_ * l_ * 4.);
149 else
150 facteur = 1. / (l_ * l_ * l_ * 8.);
151
152 for (int i = 0; i < n; i++)
153 {
154 const double x = coords(i,0);
155 const double y = coords(i,1);
156 const double z = (dim==3) ? coords(i,2) : 0.;
157 double r = facteur;
158 if (x > l_ || x < -l_
159 || y > l_ || y < -l_
160 || z > l_ || z < -l_)
161 r = 0.;
162 result[i] = r;
163 }
164 break;
165 }
166 case CHAPEAU:
167 {
168 const double L2D = l_*l_*l_*l_;
169 const double L3D = L2D*l_*l_;
170 double facteur;
171 if (dim==3)
172 facteur = 1. / L3D;
173 else
174 facteur = 1. / (L2D * l_);
175 const int nbis = coords.dimension(0);
176 for (int i = 0; i < nbis; i++)
177 {
178 const double x = coords(i, 0);
179 const double y = coords(i, 1);
180 const double z = (dim == 3) ? coords(i, 2) : 0.;
181 double resu = 0.;
182 const double ax = std::fabs(x);
183 const double ay = std::fabs(y);
184 const double az = std::fabs(z);
185 if (ax <= l_ && ay <= l_ && az <= l_)
186 resu = (l_-ax) * (l_-ay) * (l_-az) * facteur;
187 result[i] = resu;
188 }
189 break;
190 }
191 case GAUSSIENNE:
192 {
193 double facteur1 = - 0.5 / (l_ * l_);
194 double facteur2 = 1. / (l_ * sqrt(2 * M_PI));
195 if (dim == 2)
196 facteur2 = facteur2 * facteur2;
197 else
198 facteur2 = facteur2 * facteur2 * facteur2;
199 for (int i = 0; i < n; i++)
200 {
201 const double x = coords(i, 0);
202 const double y = coords(i, 1);
203 const double z = (dim == 3) ? coords(i, 2) : 0.;
204 const double k = (x*x + y*y + z*z) * facteur1;
205 result[i] = exp(k) * facteur2;
206 }
207 break;
208 }
209 case QUADRA:
210 {
211 for (int i = 0; i < n; i++)
212 {
213 const double x = coords(i, 0);
214 const double y = coords(i, 1);
215 const double z = (dim == 3) ? coords(i, 2) : 0.;
216 double resu = 0;
217 if (std::fabs(x) < l_ && std::fabs(y) < l_ && std::fabs(z) < l_)
218 {
219 resu = fonction_quadra(x,l_) * fonction_quadra(y,l_);
220 if (dim == 3)
221 resu *= fonction_quadra(z,l_);
222 }
223 result[i] = resu;
224 }
225 break;
226 }
227 default:
228 {
229 Cerr << "Error in Moyenne_volumique::eval() : filter function is not initialized." << finl;
230 exit();
231 }
232 }
233}
234
235/*! @brief Cherche le champ de nom "nom_champ" dans le probleme de nom "nom_pb" dans les objers de l'interprete.
236 *
237 * Methode appelee par traiter_champs()
238 *
239 */
241 const Nom& nom_champ,
242 OBS_PTR(Champ_base) & ref_champ)
243{
244 Probleme_base& pb = ref_cast(Probleme_base, objet(nom_pb));
245 // Le champ est-il defini dans les postraitements (statistiques) ?
246 const int nb_post = pb.postraitements().size();
247 Motcle mc_nom_champ(nom_champ);
248 for (int i_post = 0; i_post < nb_post; i_post++)
249 {
250 if (sub_type(Postraitement_base, pb.postraitements()[i_post].valeur()))
251 {
252 Postraitement& post = ref_cast(Postraitement, pb.postraitements()[i_post].valeur());
254 const int nstat = stats.size();
255 for (int i_stat = 0; i_stat < nstat; i_stat++)
256 {
257 Motcle tmp(stats[i_stat]->le_nom() );
258
259 if (tmp == mc_nom_champ)
260 {
261 Operateur_Statistique_tps_base& stat = stats[i_stat].valeur();
262 ref_cast_non_const(DoubleTab, stat.integrale().le_champ_calcule().valeurs()) = stat.calculer_valeurs();
263 ref_champ = stat.integrale().le_champ_calcule();
264 return 1;
265 }
266 }
267 }
268 }
269
270 ref_champ = pb.get_champ(nom_champ);
271 return 1;
272}
273
274/*! @brief fonction outil permettant de faire les calculs et d'ecrire le resultat dans un fichier lata pour tous les champs d'un type donne de la liste noms_champs.
275 *
276 * Methode appelee par interpreter()
277 * type_champ=0 => traiter les champs aux elements
278 * type_champ=1 => traiter les champs aux faces
279 *
280 */
282 const Nom& nom_pb, const Nom& nom_dom,
283 const DoubleTab& coords,
284 Format_Post_base& post,
285 double temps,
286 const Motcle& localisation)
287{
288 const Domaine& dom_post = ref_cast(Domaine, objet(nom_dom));
289 const int nb_champs = noms_champs.size();
290 if (nb_champs == 0)
291 return;
292
293 OBS_PTR(Champ_base) ref_champ;
294 OBS_PTR(Domaine_VF) ref_domaine_vf;
295 int i_champ;
296 // ************************************
297 // Calcul du nombre total de composantes et de ref_domaine_vf
298 int nb_compo_tot = 0;
299 for (i_champ = 0; i_champ < nb_champs; i_champ++)
300 {
301 get_champ(nom_pb, noms_champs[i_champ], ref_champ);
302 const Champ_base& champ = ref_champ.valeur();
303 const Domaine_VF& zvf = ref_cast(Domaine_VF, champ.domaine_dis_base());
304 if (i_champ == 0)
305 {
306 ref_domaine_vf = zvf;
307 }
308 else
309 {
310 if (& (ref_domaine_vf.valeur()) != & zvf)
311 {
312 Cerr << "Error in Moyenne_volumique::traiter_champs all the fields must be discretized on the same Domaine." << finl;
313 barrier();
314 exit();
315 }
316 }
317 const int nb_compo = champ.nb_comp();
318 nb_compo_tot += nb_compo;
319 }
320
321 const Domaine_VF& domaine_source = ref_domaine_vf.valeur();
322
323 // ************************************
324 // Construction d'un gros tableau contenant toutes les valeurs a traiter plus la porosite
325 DoubleTab valeurs_src;
326 const int nb_lignes = domaine_source.nb_elem();
327 valeurs_src.resize(nb_lignes, nb_compo_tot + 1);
328 int count = 0;
329 {
330 DoubleTab tmp_val;
331 IntVect liste_elems(nb_lignes);
332 for (int i = 0; i < nb_lignes; i++)
333 liste_elems[i] = i;
334 const DoubleTab& xp = domaine_source.xp();
335 for (i_champ = 0; i_champ < nb_champs; i_champ++)
336 {
337 get_champ(nom_pb, noms_champs[i_champ], ref_champ);
338 const Champ_base& champ = ref_champ.valeur();
339 const int nb_compo = champ.nb_comp();
340 tmp_val.reset();
341 tmp_val.resize(nb_lignes, nb_compo);
342 champ.valeur_aux_elems(xp, liste_elems, tmp_val);
343
344 for (int i = 0; i < nb_lignes; i++)
345 for (int j = 0; j < nb_compo; j++)
346 valeurs_src(i, count+j) = tmp_val(i, j);
347 count += nb_compo;
348
349 Cout << "Field name = " << ref_champ->le_nom()
350 << " Field type = " << ref_champ->que_suis_je() << finl;
351 }
352 }
353 // et une colonne de 1:
354 for (int i = 0; i < nb_lignes; i++)
355 valeurs_src(i, count) = 1.;
356
357 // Tableau de resultats:
358 const int nb_coords = coords.dimension(0);
359 DoubleTab resu(nb_coords, nb_compo_tot + 1);
360
361 // ************************************
362 // Calcul de tous les produits de convolution
363
364 calculer_convolution_champ_elem(domaine_source,
365 valeurs_src,
366 coords,
367 resu);
368 Noms nom_dir;
369 nom_dir.add("_X");
370 nom_dir.add("_Y");
371 nom_dir.add("_Z");
372 count = 0;
373 for (i_champ = 0; i_champ < nb_champs; i_champ++)
374 {
375 get_champ(nom_pb, noms_champs[i_champ], ref_champ);
376 const Champ_base& champ = ref_champ.valeur();
377 const int nb_compo = champ.nb_comp();
378 DoubleTab extrait(nb_coords, nb_compo);
379 for (int i = 0; i < nb_coords; i++)
380 for (int j = 0; j < nb_compo; j++)
381 extrait(i, j) = resu(i, count + j);
382
383 Cout << "Post writting " << champ.le_nom() << finl;
384 Nom nature("scalar");
385 if (champ.nature_du_champ()==vectoriel) nature="vector";
386 post.ecrire_champ(dom_post,
387 champ.unites(),
388 champ.noms_compo(),
389 -1 /* ecrire toutes les composantes */, temps,
390 noms_champs[i_champ], nom_dom, localisation,nature, extrait);
391
392 count += nb_compo;
393 }
394 // Derniere colonne (porosite)
395 const int nb_compo = 1;
396 DoubleTab extrait(nb_coords, nb_compo);
397 for (int i = 0; i < nb_coords; i++)
398 for (int j = 0; j < nb_compo; j++)
399 extrait(i, j) = resu(i, count + j);
400
401 Noms noms_compo;
402 Noms unites;
403 Nom nom_moyenne;
404 unites.add("m3");
405 noms_compo.add("porosite");
406 nom_moyenne = "porosite";
407 Cout << "Porosity post writing" << finl;
408
409 post.ecrire_champ(dom_post, unites, noms_compo, -1 /* ecrire toutes les composantes */,
410 temps,
411 nom_moyenne, nom_dom, localisation, "scalar",extrait);
412}
413
414/*! @brief Lecture des parametres dans le jeu de donnees.
415 *
416 * Format attendu: Moyenne_volumique {
417 * nom_pb NOM_DU_PROBLEME (ou chercher les champs sources)
418 * nom_domaine DOMAINE_CIBLE (on evalue la convolution aux elements de ce domaine)
419 * noms_champs N CHAMP1 CHAMP2 ... (noms des champs a filtrer dans le probleme)
420 * [ nom_fichier_post NOM_SANS_EXTENSION ] (soit on donne nom_fichier et format_post,
421 * soit on donne fichier_post)
422 * [ format_post lata|lml|med|... ] (par defaut lata)
423 * [ fichier_post Format_Post_XXX { ... } ] (lecture par readOn du Format_Post_XXX)
424 * fonction_filtre ... (format : voir Moyenne_volumique::readOn() )
425 * [ localisation ELEM|SOM ]
426 * }
427 *
428 */
430{
431 Cerr << "Starting of Moyenne_volumique::interpreter" << finl;
432 Nom nom_pb, nom_dom;
433 Motcles noms_champs;
434 Param param(que_suis_je() + Nom("::interpreter()"));
435 const int id_elem = 0;
436 const int id_som = 1;
437 int localisation = id_elem; // par defaut
438 Motcle format_post("lata_v1");
439 Nom nom_fichier_post;
440 OWN_PTR(Format_Post_base) fichier_post;
441 param.ajouter("nom_pb", & nom_pb, Param::REQUIRED); // XD_ADD_P ref_Pb_base
442 // XD_CONT name of the problem where the source fields will be searched.
443 param.ajouter("nom_domaine", & nom_dom, Param::REQUIRED); // XD_ADD_P ref_domaine
444 // XD_CONT name of the destination domain (for example, it can be a coarser mesh, but for optimal performance in
445 // XD_CONT parallel, the domain should be split with the same algorithm as the computation mesh, eg, same tranche
446 // XD_CONT parameters for example)
447 param.ajouter("noms_champs", & noms_champs, Param::REQUIRED); // XD_ADD_P listchaine
448 // XD_CONT name of the source fields (these fields must be accessible from the postraitement) N source_field1
449 // XD_CONT source_field2 ... source_fieldN
450 param.ajouter("fichier_post", & fichier_post);
451 param.ajouter("format_post", & format_post); // XD_ADD_P chaine
452 // XD_CONT gives the fileformat for the result (by default : lata)
453 param.ajouter("nom_fichier_post", & nom_fichier_post); // XD_ADD_P chaine
454 // XD_CONT indicates the filename where the result is written
455 // L'objet Moyenne_volumique est un interprete, mais c'est aussi un objet
456 // dont la seule propriete est la fonction filtre a utiliser... astuce:
457 // on appelle le readOn de la classe pour lire la fonction filtre.
458 param.ajouter("fonction_filtre", this, Param::REQUIRED); // XD_ADD_P bloc_lecture
459 // XD_CONT to specify the given filter NL2 Fonction_filtre {NL2 type filter_typeNL2 demie-largeur lNL2 [ omega w ] NL2
460 // XD_CONT [ expression string ]NL2 } NL2 NL2 type filter_type : This parameter specifies the filtering function.
461 // 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
462 // XD_CONT Chapeau is a hat filter (product of hat filters in each direction) centered on the origin, the half-width
463 // XD_CONT of the filter being l and its integral being 1.NL2 Quadra is a 2nd order filter.NL2 Gaussienne is a
464 // XD_CONT normalized gaussian filter of standard deviation sigma in each direction (all field elements outside a
465 // XD_CONT cubic box defined by clipping_half_width are ignored, hence, taking clipping_half_width=2.5*sigma yields an
466 // XD_CONT integral of 0.99 for a uniform unity field).NL2 Parser allows a user defined function of the x,y,z
467 // XD_CONT variables. All elements outside a cubic box defined by clipping_half_width are ignored. The parser is much
468 // XD_CONT slower than the equivalent c++ coded function...NL2 NL2 demie-largeur l : This parameter specifies the half
469 // XD_CONT width of the filterNL2 [ omega w ] : This parameter must be given for the gaussienne filter. It defines the
470 // XD_CONT standard deviation of the gaussian filter.NL2 [ expression string] : This parameter must be given for the
471 // XD_CONT parser filter type. This expression will be interpreted by the math parser with the predefined variables x,
472 // XD_CONT y and z.
473 param.ajouter("localisation", & localisation); // XD_ADD_P chaine(into=["elem","som"])
474 // XD_CONT indicates where the convolution product should be computed: either on the elements or on the nodes of the
475 // XD_CONT destination domain.
476 param.dictionnaire("ELEM", id_elem);
477 param.dictionnaire("SOM", id_som);
479
480 // on recupere le domaine
481 const Domaine& dom = ref_cast(Domaine, objet(nom_dom));
482 if (noms_champs.size() == 0)
483 {
484 Cerr << "Moyenne_volumique : no field to treat" << finl;
485 return is;
486 }
487 Cerr << "Writing of the post-processing domain : " << nom_dom << finl;
488 OBS_PTR(Champ_base) ref_champ;
489 get_champ(nom_pb, noms_champs[0], ref_champ);
490 const double temps = ref_champ->temps();
491 if (!fichier_post)
492 {
493 if (nom_fichier_post == "??")
494 {
495 Cerr << "Error in Moyenne_volumique::interpreter:\n"
496 << " missing NOM_FICHIER_POST or FICHIER_POST keyword" << finl;
497 barrier();
498 exit();
499 }
500 if (format_post == "lata_v2")
501 format_post = "lata";
502 // Astuce pour permettre le cas test de non regression en sequentiel et en parallele:
503 // (il faut que le nom du fichier de sortie soit le nom du cas)
504 if (nom_fichier_post == "NOM_DU_CAS")
505 {
506 Cerr << "Post filename = NOM_DU_CAS => using " << nom_du_cas() << " instead" << finl;
507 nom_fichier_post = nom_du_cas();
508 }
509 fichier_post.typer(Motcle("FORMAT_POST_") + format_post);
510 fichier_post->initialize(nom_fichier_post, 1 /* binaire */, "SIMPLE");
511 }
512 else
513 {
514 if (nom_fichier_post != "??")
515 {
516 Cerr << "Error in Moyenne_volumique::interpreter:\n"
517 << " you cannot give NOM_FICHIER_POST and FICHIER_POST. Choose one" << finl;
518 barrier();
519 exit();
520 }
521 }
522 Format_Post_base& post = fichier_post.valeur();
523 post.ecrire_entete(temps, 0 /*reprise*/, 1 /* premier post */);
524 post.ecrire_domaine(dom, 1 /* premier_post */);
525 post.ecrire_temps(temps);
526
527 // Coordonnees des centres des elements du domaine destination
528 DoubleTab coords;
529 if (localisation == id_elem)
530 {
531 dom.calculer_centres_gravite(coords);
532 // Le tableau contient aussi les elements virtuels et pas d'espace virtuel. bouh.
533 coords.resize(dom.nb_elem(), coords.dimension(1));
534 }
535 else
536 {
537 coords = dom.les_sommets();
538 }
539
540 Motcle loc("ELEM");
541 if (localisation == id_som)
542 loc = "SOM";
543 traiter_champs(noms_champs,
544 nom_pb,
545 nom_dom,
546 coords,
547 post,
548 temps,
549 loc);
550 int fin=1;
551 post.finir(fin);
552 return is;
553}
554
555/*! @brief : classe outil utilisee en interne dans calculer_convolution()
556 *
557 */
559{
560public:
561 Calcul_integrale_locale(const Domaine_VF& domaine_source,
562 const Moyenne_volumique& filter,
563 const DoubleTab& champ_source);
564 void calculer(double x, double y, double z, ArrOfDouble& resu);
565
566protected:
568 Octree_Double octree_;
570 const DoubleTab& champ_source_;
571 // Tableaux temporaires utilises dans calculer():
572 ArrOfInt liste_elems_;
573 DoubleTab filter_coords_;
574 ArrOfDouble filter_results_;
576};
577
578/*! @brief constructeur de la classe outil.
579 *
580 * .. Voir Moyenne_volumique::calculer_convolution()
581 *
582 */
584 const Moyenne_volumique& filter,
585 const DoubleTab& champ_source) :
586 domaine_source_(domaine_source),
587 filter_(filter),
588 champ_source_(champ_source)
589{
590
591
592
593 // Construction d'un octree contenant les centres des elements
594 // On copie le tableau car il sera retaille :
595 DoubleTab coords = domaine_source.xp();
596 nb_items_reels_ = domaine_source.nb_elem();
597 // Le tableau xp est dimensionne avec dimension(0)=nb_elem_tot. On le retaille a nb_elem
598 coords.resize(nb_items_reels_, coords.dimension(1));
599 if (champ_source.dimension(0) != nb_items_reels_)
600 {
601 Cerr << "Error in Calcul_integrale_locale::Calcul_integrale_locale() :\n"
602 << " The source field is not discretized at the elements" << finl;
603 Process::barrier();
604 Process::exit();
605 }
606 octree_.build_nodes(coords, 0 /* no virtual items */);
607}
608
609/*! @brief evalue le produit de convolution "filter_ * champ_source_" au point x,y,z et stocke le resultat dans resu.
610 *
611 * On determine les elements a utiliser en fonction
612 * de la taille du filtre en utilisant une octree.
613 * On suppose que le champ source est aux elements.
614 * Methode appelee par Moyenne_volumique::calculer_convolution()
615 *
616 */
617void Calcul_integrale_locale::calculer(const double x, const double y, const double z,
618 ArrOfDouble& resu)
619{
620 const double box_size = filter_.box_size();
621 octree_.search_elements_box(x - box_size, y - box_size, z - box_size,
622 x + box_size, y + box_size, z + box_size,
624
625 const DoubleTab& coord_items = domaine_source_.xp();
626
627 const int nb_items = liste_elems_.size_array();
628 const int dim = Objet_U::dimension;
629 filter_coords_.resize(nb_items, dim);
630 for (int i = 0; i < nb_items; i++)
631 {
632 const int item = liste_elems_[i];
633 assert(item < nb_items_reels_);
634 filter_coords_(i, 0) = coord_items(item, 0) - x;
635 filter_coords_(i, 1) = coord_items(item, 1) - y;
636 if (dim == 3)
637 filter_coords_(i, 2) = coord_items(item, 2) - z;
638 }
639 filter_results_.resize_array(nb_items);
641
642 const DoubleVect& volumes = domaine_source_.volumes();
643 const int nb_comp = champ_source_.dimension(1);
644 resu = 0.;
645 for (int i = 0; i < nb_items; i++)
646 {
647 const int item = liste_elems_[i];
648 const double valeur_filtre = filter_results_[i];
649 const double volume = volumes(item);
650 const double facteur = valeur_filtre * volume;
651 for (int j = 0; j < nb_comp; j++)
652 {
653 // L'integrale est discretisee grossierement comme le produit des
654 // valeurs au centre de l'element fois le volume de l'element:
655 const double valeur_champ = champ_source_(item, j);
656 resu[j] += valeur_champ * facteur;
657 }
658 }
659}
660
661/*! @brief methode generale pour calculer une convolution a partir d'un champ aux elements ou aux faces.
662 *
663 * Methode appelee par calculer_convolution_champ_elem()
664 * et calculer_convolution_champ_face()
665 *
666 */
668 const DoubleTab& champ_source,
669 const DoubleTab& coords_to_compute,
670 DoubleTab& resu) const
671{
672 assert(resu.dimension(0) == coords_to_compute.dimension(0));
673 const int dim = Objet_U::dimension;
674 const int nbproc = Process::nproc();
675 const int nb_coords_to_compute = coords_to_compute.dimension(0);
676 const int nb_coords_max = mp_max(nb_coords_to_compute);
677
678 int nb_comp;
679 nb_comp = champ_source.line_size();
680 assert(resu.line_size() == nb_comp);
681
682 DoubleTab coords(nbproc, 3);
683 ArrOfInt flag(nbproc);
684 ArrOfDouble resu_partiel(nb_comp);
685 DoubleTab resu_partiels(nbproc, nb_comp);
686
687 Calcul_integrale_locale integrale_locale(domaine_source,
688 *this,
689 champ_source);
690
691 // Boucle sur les coordonnees x locales pour lesquelles on veut calculer l'integrale I(x).
692 // Si x est pres du bord, le support de la fonction filtre couvre des processeurs voisins
693 // qu'il faut ajouter. Pour chaque coordonnees, on demande a tous les autres processeurs
694 // de calculer la contribution. Donc on boucle sur le max du nombre de coordonnees pour
695 // synchroniser les procs:
696 int i, j;
697 for (int i_coord = 0; i_coord < nb_coords_max; i_coord++)
698 {
699 // Chaque processeur envoie la coordonnee a calculer a tous les processeurs:
700 if (i_coord < nb_coords_to_compute)
701 {
702 for (j = 0; j < dim; j++)
703 {
704 double x = coords_to_compute(i_coord, j);
705 for (i = 0; i < nbproc; i++)
706 coords(i, j) = x;
707 }
708 flag = 1;
709 }
710 else
711 {
712 flag = 0;
713 }
714 envoyer_all_to_all(coords, coords);
715 envoyer_all_to_all(flag, flag);
716 // On a dans coord(pe, i) les coordonnees demandees par chaque processeur et
717 // flag[pe] indique si le processeur a demande une coordonnee ou s'il a fini
718 // sa liste coords_to_compute.
719 // On calcule maintenant la contribution du processeur local aux integrales I(x)
720 // pour ces coordonnees. En general, le processeur qui a cette coordonnee chez lui
721 // a beaucoup de travail pour celle-ci et presque rien a faire pour les autres coordonnees
722 // (si la coordonnee est loin du domaine, l'octree trouve tres rapidement la liste vide).
723 // Donc les calculs sont a peu pres equilibres sur les processeurs.
724 for (i = 0; i < nbproc; i++)
725 {
726 if (flag[i])
727 {
728 integrale_locale.calculer(coords(i, 0), coords(i, 1), coords(i, 2), resu_partiel);
729 for (j = 0; j < nb_comp; j++)
730 resu_partiels(i, j) = resu_partiel[j];
731 }
732 }
733 // On renvoie a chaque processeur la contribution du processeur local pour la coordonnee
734 // qu'il a demande:
735 envoyer_all_to_all(resu_partiels, resu_partiels);
736 // Le resultat est la somme des contributions de tous les processeurs:
737 if (i_coord < nb_coords_to_compute)
738 {
739 for (j = 0; j < nb_comp; j++)
740 {
741 double x = 0.;
742 for (i = 0; i < nbproc; i++)
743 x += resu_partiels(i, j);
744 resu(i_coord, j) = x;
745 }
746 }
747 }
748}
749
750/*! @brief Calcule le produit de convolution entre la fonction filtre et le champ "champ_source" qui doit etre discretise aux elements de la "domaine_source".
751 *
752 * Le tableau resu aura le meme nombre de colonnes que le tableau "champ_source", et
753 * le meme nombre de lignes que le tableau coords_to_compute.
754 * On suppose que la fonction filtre a un support inclu dans un cube de demi-cote box-size
755 * centre sur l'origine (on ne calcule pas la contribution des elements hors de ce cube).
756 *
757 */
759 const DoubleTab& champ_source,
760 const DoubleTab& coords_to_compute,
761 DoubleTab& resu) const
762{
763 assert(champ_source.dimension(0) == domaine_source.domaine().nb_elem());
764 calculer_convolution(domaine_source, champ_source,
765 coords_to_compute, resu);
766}
767
768/*! @brief Idem que calculer_convolution_champ_elem pour un champ VDF aux faces.
769 *
770 * (on suppose que le champ source est un champ vectoriel contenant pour chaque face
771 * la composante normale du champ a cette face)
772 * Pour chaque colonne du tableau champ_source, on remplit "dimension" colonnes
773 * du tableau resu : la premiere utilisant uniquement les faces de normale X, la deuxieme
774 * avec les faces de normale Y, etc...
775 *
776 */
778 const DoubleTab& champ_source,
779 const DoubleTab& coords_to_compute,
780 DoubleTab& resu) const
781{
782 Cerr << " Moyenne_volumique::calculer_convolution_champ_face is not coded" << finl;
783 exit();
784}
: classe outil utilisee en interne dans calculer_convolution()
const DoubleTab & champ_source_
void calculer(double x, double y, double z, ArrOfDouble &resu)
evalue le produit de convolution "filter_ * champ_source_" au point x,y,z et stocke le resultat dans ...
const Moyenne_volumique & filter_
Calcul_integrale_locale(const Domaine_VF &domaine_source, const Moyenne_volumique &filter, const DoubleTab &champ_source)
constructeur de la classe outil.
const Domaine_VF & domaine_source_
DoubleTab & valeurs() override
Surcharge Champ_base::valeurs() Renvoie le tableau des valeurs.
classe Champ_base Cette classe est la base de la hierarchie des champs.
Definition Champ_base.h:43
void calculer_centres_gravite(DoubleTab_t &xp) const
Calcule les centres de gravites des elements du domaine.
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
Classe de base des formats de postraitements pour les champs (lata, med, cgns, lml,...
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)
Ecriture d'un champ dans le fichier de postraitement.
virtual int ecrire_temps(const double temps)
Commence l'ecriture d'un pas de temps.
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)
Ecriture d'un maillage.
const Champ_Fonc_base & le_champ_calcule() const
Classe de base des objets "interprete".
Definition Interprete.h:38
static Objet_U & objet(const Nom &)
Voir Interprete_bloc::objet_global() BM: la classe Interprete n'est pas le meilleur endroit pour cett...
Une chaine de caractere (Nom) en majuscules.
Definition Motcle.h:26
Un tableau d'objets de la classe Motcle.
Definition Motcle.h:63
: cet interprete permet, a la fin du calcul (apres "resoudre"), de calculer et de stocker dans un fic...
virtual void calculer_convolution_champ_elem(const Domaine_VF &domaine_source, const DoubleTab &champ_source, const DoubleTab &coords_to_compute, DoubleTab &resu) const
Calcule le produit de convolution entre la fonction filtre et le champ "champ_source" qui doit etre d...
virtual void calculer_convolution_champ_face(const Domaine_VF &domaine_source, const DoubleTab &champ_source, const DoubleTab &coords_to_compute, DoubleTab &resu) const
Idem que calculer_convolution_champ_elem pour un champ VDF aux faces.
int get_champ(const Nom &nom_pb, const Nom &nom_champ, OBS_PTR(Champ_base) &ref_champ)
Cherche le champ de nom "nom_champ" dans le probleme de nom "nom_pb" dans les objers de l'interprete.
virtual void calculer_convolution(const Domaine_VF &domaine_source, const DoubleTab &champ_source, const DoubleTab &coords_to_compute, DoubleTab &resu) const
methode generale pour calculer une convolution a partir d'un champ aux elements ou aux 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)
fonction outil permettant de faire les calculs et d'ecrire le resultat dans un fichier lata pour tous...
Entree & interpreter(Entree &) override
Lecture des parametres dans le jeu de donnees.
virtual void eval_filtre(const DoubleTab &coords, ArrOfDouble &result) const
Evalue la fonction filtre en chaque coordonnee coord Methode appelee dans la classe Calcul_integrale_...
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
Un tableau de chaine de caracteres (VECT(Nom)).
Definition Noms.h:26
friend class Entree
Definition Objet_U.h:76
static int dimension
Definition Objet_U.h:99
const Nom & que_suis_je() const
renvoie la chaine identifiant la classe.
Definition Objet_U.cpp:104
virtual Entree & readOn(Entree &)
Lecture d'un Objet_U sur un flot d'entree Methode a surcharger.
Definition Objet_U.cpp:293
static double precision_geom
Definition Objet_U.h:86
static const Nom & nom_du_cas()
Renvoie une reference constante vers le nom du cas.
Definition Objet_U.cpp:146
virtual const Nom & le_nom() const
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
Definition Objet_U.cpp:319
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Operateur_Statistique_tps_base Represente des operations statistiques sur les champs.
virtual const Integrale_tps_Champ & integrale() const =0
virtual DoubleTab calculer_valeurs() const =0
classe Operateurs_Statistique_tps Cette classe represente une liste d'operateurs statistiques en temp...
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
Classe de base pour l'ensemble des postraitements.
classe Postraitement La classe est dotee -d une liste de champs generiques champs_post_complet_ qui c...
Operateurs_Statistique_tps & les_statistiques()
classe Probleme_base C'est un Probleme_U qui n'est pas un couplage.
const Champ_base & get_champ(const Motcle &nom) const override
Postraitements & postraitements()
static double mp_max(double)
Definition Process.cpp:376
static int nproc()
renvoie le nombre de processeurs dans le groupe courant Voir Comm_Group::nproc() et PE_Groups::curren...
Definition Process.cpp:104
static void barrier()
Synchronise tous les processeurs du groupe courant (attend que tous les processeurs soient arrives a ...
Definition Process.cpp:136
static void exit(int exit_code=-1)
Routine de sortie de TRUST dans une region Kokkos.
Definition Process.cpp:455
Classe de base des flux de sortie.
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