TrioCFD 1.9.8
TrioCFD documentation
Loading...
Searching...
No Matches
Domaine_Poly_base.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 <Linear_algebra_tools_impl.h>
17#include <Connectivite_som_elem.h>
18#include <MD_Vector_composite.h>
19#include <Domaine_Poly_base.h>
20#include <MD_Vector_tools.h>
21#include <Interface_blocs.h>
22#include <Comm_Group_MPI.h>
23#include <Quadrangle_VEF.h>
24#include <communications.h>
25#include <Matrice_Morse.h>
26#include <Segment_poly.h>
27#include <Hexaedre_VEF.h>
28#include <Matrix_tools.h>
29#include <unordered_map>
30#include <Array_tools.h>
31#include <Quadri_poly.h>
32#include <Tetra_poly.h>
33#include <TRUSTLists.h>
34#include <Tetraedre.h>
35#include <Rectangle.h>
36#include <PE_Groups.h>
37#include <Hexa_poly.h>
38#include <Tri_poly.h>
39#include <Hexaedre.h>
40#include <Triangle.h>
41#include <EFichier.h>
42#include <SFichier.h>
43#include <Segment.h>
44#include <Domaine.h>
45#include <Scatter.h>
46#include <EChaine.h>
47#include <unistd.h>
48#include <Lapack.h>
49#include <numeric>
50#include <vector>
51#include <cfloat>
52#include <tuple>
53#include <cmath>
54#include <cfenv>
55#include <set>
56#include <map>
57bool polymac_flica5=false;
58Implemente_base(Domaine_Poly_base,"Domaine_Poly_base",Domaine_VF);
59
61{
63 os << "____ h_carre "<<finl;
64 os << h_carre << finl;
65 os << "____ type_elem_ "<<finl;
66 os << type_elem_.valeur() << finl;
67 os << "____ nb_elem_std_ "<<finl;
68 os << nb_elem_std_ << finl;
69 os << "____ volumes_entrelaces_ "<<finl;
70 volumes_entrelaces_.ecrit(os);
71 os << "____ face_normales_ "<<finl;
72 face_normales_.ecrit(os);
73 os << "____ nb_faces_std_ "<<finl;
74 os << nb_faces_std_ << finl;
75 os << "____ rang_elem_non_std_ "<<finl;
76 rang_elem_non_std_.ecrit(os);
77 return os;
78}
79
81{
83
84 os << h_carre << finl;
85 os << type_elem_.valeur() << finl;
86 os << nb_elem_std_ << finl;
87 os << volumes_entrelaces_ << finl;
88 os << face_normales_ << finl;
89 os << xp_ << finl;
90 os << xv_ << finl;
91 os << nb_faces_std_ << finl;
92 os << rang_elem_non_std_ << finl;
93 return os;
94}
95
97{
99 is >> h_carre;
100
101 /* read type_elem */
102 {
103 Nom type;
104 is >> type;
105 if (type == "Tri_poly")
106 type_elem_ = Tri_poly();
107 else if (type == "Tetra_poly")
108 type_elem_ = Tetra_poly();
109 else if (type == "Quadri_poly")
110 type_elem_ = Quadri_poly();
111 else if (type == "Hexa_poly")
112 type_elem_ = Hexa_poly();
113 else
114 {
115 Cerr << type << " is not an Elem_poly !" << finl;
117 }
118 }
119
120 is >> nb_elem_std_ ;
121 is >> volumes_entrelaces_ ;
122 is >> face_normales_ ;
123 is >> xp_;
124 is >> xv_;
125 is >> nb_faces_std_ ;
126 is >> rang_elem_non_std_ ;
127 return is;
128}
129
130
131void Domaine_Poly_base::typer_elem(Domaine& domaine_geom)
132{
133 const Elem_geom_base& elem_geom = domaine_geom.type_elem().valeur();
134
135 if (sub_type(Rectangle, elem_geom))
136 {
137 domaine_geom.typer("Quadrangle");
138 }
139 else if (sub_type(Hexaedre, elem_geom))
140 domaine_geom.typer("Hexaedre_VEF");
141
142 const Nom& type_elem_geom = domaine_geom.type_elem()->que_suis_je();
143
144 Cerr << "Elem_poly => type geometrique : " << type_elem_geom << finl;
145
146 Nom type;
147 if (type_elem_geom == "Triangle")
148 type = "Tri_poly";
149 else if (type_elem_geom == "Tetraedre")
150 type = "Tetra_poly";
151 else if (type_elem_geom == "Quadrangle")
152 type = "Quadri_poly";
153 else if (type_elem_geom == "Hexaedre_VEF")
154 type = "Hexa_poly";
155 else if (type_elem_geom == "Segment")
156 type = "Segment_poly";
157 else if (type_elem_geom == "Polygone")
158 type = "Polygone_poly";
159 else if (type_elem_geom == "Polyedre")
160 type = "Polyedre_poly";
161 else
162 {
163 Cerr << "problem in Elem_poly::typer" << finl;
165 }
166 type_elem_.typer(type);
167 Cerr << "Elem_poly => type retenu : " << type_elem_->que_suis_je() << finl;
168}
169
171{
172 const Elem_geom_base& elem_geom = domaine().type_elem().valeur();
173
174 if (sub_type(Segment_poly,type_elem_.valeur()))
175 {
176 if (!sub_type(Segment,elem_geom))
177 {
178 Cerr << " The type of the element " << elem_geom.que_suis_je() << " is incorrect" << finl;
180 }
181 }
182 else if (sub_type(Tri_poly,type_elem_.valeur()))
183 {
184 if (!sub_type(Triangle,elem_geom))
185 {
186 Cerr << " The type of the element " << elem_geom.que_suis_je() << " is incorrect" << finl;
187 Cerr << " Only the Triangle type is compatible with the PolyMAC_MPFA discretisation in dimension 2" << finl;
188 Cerr << " You must triangulate the domain when using the TRUST mesher" ;
189 Cerr << " This can be done by adding : Trianguler nom_dom" << finl;
191 }
192 }
193 else if (sub_type(Tetra_poly,type_elem_.valeur()))
194 {
195 if (!sub_type(Tetraedre,elem_geom))
196 {
197 Cerr << " The type of the element " << elem_geom.que_suis_je() << " is incorrect" << finl;
198 Cerr << " Only the Tetrahedral type is compatible with the PolyMAC_MPFA discretisation in dimension 3" << finl;
199 Cerr << " You must tetrahedrize the domain when using the TRUST mesher" ;
200 Cerr << " This can be done by adding : Tetraedriser nom_dom" << finl;
202 }
203 }
204
205 else if (sub_type(Quadri_poly,type_elem_.valeur()))
206 {
207
208 if (!sub_type(Quadrangle_VEF,elem_geom))
209 {
210 Cerr << " The type of the element " << elem_geom.que_suis_je() << " is incorrect" << finl;
212 }
213 }
214 else if (sub_type(Hexa_poly,type_elem_.valeur()))
215 {
216
217 if (!sub_type(Hexaedre_VEF,elem_geom))
218 {
219 Cerr << " The type of the element " << elem_geom.que_suis_je() << " is incorrect" << finl;
221 }
222 }
223}
224
226{
227 // Correction du tableau facevoisins:
228 // A l'issue de Domaine_VF::discretiser(), les elements voisins 0 et 1 d'une
229 // face sont les memes sur tous les processeurs qui possedent la face.
230 // Si la face est virtuelle et qu'un des deux elements voisins n'est
231 // pas connu (il n'est pas dans l'epaisseur du joint), l'element voisin
232 // vaut -1. Cela peut etre un voisin 0 ou un voisin 1.
233 // On corrige les faces virtuelles pour que, si un element voisin n'est
234 // pas connu, alors il est voisin1. Le voisin0 est donc toujours valide.
235 IntTab& face_vois = face_voisins();
236 const int debut = nb_faces();
237 const int fin = nb_faces_tot();
238 for (int i = debut; i < fin; i++)
239 if (face_voisins(i, 0) == -1)
240 {
241 face_vois(i, 0) = face_vois(i, 1);
242 face_vois(i, 1) = -1;
243 }
244}
245
247{
251
253
254 face_normales_.resize(0, dimension);
257
260
264
265 /* ordre canonique dans elem_faces_ */
266 std::map<std::array<double, 3>, int> xv_fsa;
267 for (int e = 0, i, j, f; e < nb_elem_tot(); e++)
268 {
269 for (i = 0, j = 0, xv_fsa.clear(); i < elem_faces_.dimension(1) && (f = elem_faces_(e, i)) >= 0; i++)
270 xv_fsa[ {{ xv_(f, 0), xv_(f, 1), dimension < 3 ? 0 : xv_(f, 2) }}] = f;
271 for (auto &&c_f : xv_fsa) elem_faces_(e, j) = c_f.second, j++;
272 }
273 //calculer_h_carre();
274}
275
277{
278 // On remplit le tableau face_normales_;
279 // Attention : le tableau face_voisins n'est pas exactement un
280 // tableau distribue. Une face n'a pas ses deux voisins dans le
281 // meme ordre sur tous les processeurs qui possedent la face.
282 // Donc la normale a la face peut changer de direction d'un
283 // processeur a l'autre, y compris pour les faces de joint.
284
285 const IntTab& face_som = face_sommets();
286 IntTab& face_vois = face_voisins();
287 const IntTab& elem_face = elem_faces();
288 const int nf_tot = nb_faces_tot();
289 for (int f = 0; f < nf_tot; f++)
290 type_elem_->normale(f, face_normales_, face_som, face_vois, elem_face, domaine());
291
292 DoubleTab old(face_normales_);
293 face_normales_.echange_espace_virtuel();
294 for (int f = 0; f < nf_tot; f++)
295 {
296 int id=1;
297 for (int d = 0; d < dimension; d++)
298 if (!est_egal(old(f,d),face_normales_(f,d)))
299 {
300 id=0;
301 if (!est_egal(old(f, d), -face_normales_(f, d)))
302 {
303 Cerr << "pb in faces_normales" << finl;
305 }
306 }
307 if (id == 0)
308 {
309 // on a change le sens de la normale, on inverse elem1 elem2
310 std::swap(face_vois(f, 0), face_vois(f, 1));
311 }
312 }
313}
314
316{
317 Cerr << "Domaine_Poly has been filled with success" << finl;
318 // calculer_h_carre();
319
320 Journal() << "Domaine_Poly_base::Modifier_pour_Cl" << finl;
321 int nb_cond_lim=conds_lim.size();
322 int num_cond_lim=0;
323 for (; num_cond_lim<nb_cond_lim; num_cond_lim++)
324 {
325 //for cl
326 const Cond_lim_base& cl = conds_lim[num_cond_lim].valeur();
327 if (sub_type(Periodique, cl))
328 {
329 //if Perio
330 const Periodique& la_cl_period = ref_cast(Periodique,cl);
331 int nb_faces_elem = domaine().nb_faces_elem();
332 const Front_VF& la_front_dis = ref_cast(Front_VF,cl.frontiere_dis());
333 int ndeb = 0;
334 int nfin = la_front_dis.nb_faces_tot();
335#ifndef NDEBUG
336 int num_premiere_face = la_front_dis.num_premiere_face();
337 int num_derniere_face = num_premiere_face+nfin;
338#endif
339 int nbr_faces_bord = la_front_dis.nb_faces();
340 assert((nb_faces()==0)||(ndeb<nb_faces()));
341 assert(nfin>=ndeb);
342 int elem1,elem2,k;
343 int face;
344 // Modification des tableaux face_voisins_ , face_normales_ , volumes_entrelaces_
345 // On change l'orientation de certaines normales
346 // de sorte que les normales aux faces de periodicite soient orientees
347 // de face_voisins(la_face_en_question,0) vers face_voisins(la_face_en_question,1)
348 // comme le sont les faces internes d'ailleurs
349
350 DoubleVect C1C2(dimension);
351 double vol,psc=0;
352
353 for (int ind_face=ndeb; ind_face<nfin; ind_face++)
354 {
355 //for ind_face
356 face = la_front_dis.num_face(ind_face);
357 if ( (face_voisins_(face,0) == -1) || (face_voisins_(face,1) == -1) )
358 {
359 int faassociee = la_front_dis.num_face(la_cl_period.face_associee(ind_face));
360 if (ind_face<nbr_faces_bord)
361 {
362 assert(faassociee>=num_premiere_face);
363 assert(faassociee<num_derniere_face);
364 }
365
366 elem1 = face_voisins_(face,0);
367 elem2 = face_voisins_(faassociee,0);
368 vol = (volumes_[elem1] + volumes_[elem2])/nb_faces_elem;
369 volumes_entrelaces_[face] = vol;
370 volumes_entrelaces_[faassociee] = vol;
371 face_voisins_(face,1) = elem2;
372 face_voisins_(faassociee,0) = elem1;
373 face_voisins_(faassociee,1) = elem2;
374 psc = 0;
375 for (k=0; k<dimension; k++)
376 {
377 C1C2[k] = xv_(face,k) - xp_(face_voisins_(face,0),k);
378 psc += face_normales_(face,k)*C1C2[k];
379 }
380
381 if (psc < 0)
382 for (k=0; k<dimension; k++)
383 face_normales_(face,k) *= -1;
384
385 for (k=0; k<dimension; k++)
386 face_normales_(faassociee,k) = face_normales_(face,k);
387 }
388 }
389 }
390 }
391
392 // PQ : 10/10/05 : les faces periodiques etant a double contribution
393 // l'appel a marquer_faces_double_contrib s'effectue dans cette methode
394 // afin de pouvoir beneficier de conds_lim.
396}
397
399{
400 const IntTab& f_e = face_voisins(), &f_s = face_sommets_;
401 const DoubleTab& xs = domaine().coord_sommets(), &nf = face_normales_;
402 const DoubleVect& fs = face_surfaces();
403 int i, j, f, s, rk = Process::me(), np = Process::nproc();
404 double sin2;
405 ArrOfDouble val(np); //sur chaque proc : { cos^2 max, indice de face, indices d'elements }
406 IntTab face(np), elem1(np), elem2(np);
407
408 //sur chaque proc : on cherche l'angle le plus grand entre un sommet et le plan de sa face
409 for (f = 0; f < nb_faces(); f++)
410 for (i = 0; i < f_s.dimension(1) && (s = f_s(f, i)) >= 0; i++)
411 if (fs(f) > 0 && (sin2 = std::pow(dot(&xs(s, 0), &nf(f, 0), &xv_(f, 0)) / fs(f), 2) / dot(&xs(s, 0), &xs(s, 0), &xv_(f, 0), &xv_(f, 0))) > val[rk])
412 val[rk] = sin2, face(rk) = f, elem1(rk) = f_e(f, 0), elem2(rk) = f_e(f, 1);
413 envoyer_all_to_all(val, val), envoyer_all_to_all(face, face), envoyer_all_to_all(elem1, elem1), envoyer_all_to_all(elem2, elem2);
414
415 for (i = j = 0, sin2=0.0; i < Process::nproc(); i++)
416 if (val[i] > sin2) sin2 = val[i], j = i;
417 double theta = asin(sqrt(sin2)) * 180 / M_PI;
418 Cerr << "Domaine_Poly_base : angle sommet/face max " << theta << " deg (proc " << j << " , face ";
419 Cerr << face(j) << " , elems " << elem1(j) << " / " << elem2(j) << " )" << finl;
420 if (theta > 1)
421 {
422 Cerr << "Domaine_Poly_base : non-planar face detected ! Please fix your mesh or call 911 ..." << finl;
424 }
425}
426
428{
429 //diverses quantites liees aux aretes
430 if (dimension > 2)
431 {
434
435 //remplissage de xa (CGs des aretes), de ta_ (vecteur tangent aux aretes) et de longueur_arete_ (longueurs des aretes)
436 xa_.resize(0, 3), ta_.resize(0, 3);
439 }
440
441 //MD_vector pour Champ_Elem_PolyMAC_HFV (elems + faces)
442 MD_Vector_composite mdc_ef;
443 mdc_ef.add_part(domaine().md_vector_elements()), mdc_ef.add_part(md_vector_faces());
444 mdv_elems_faces.copy(mdc_ef);
445
446 //MD_vector pour Champ_Face_PolyMAC_HFV (faces + aretes)
447 MD_Vector_composite mdc_fa;
448 mdc_fa.add_part(md_vector_faces()), mdc_fa.add_part(dimension < 3 ? domaine().md_vector_sommets() : md_vector_aretes());
449 mdv_faces_aretes.copy(mdc_fa);
450
451 //Ajout face_arete connectivite (pour STT a mettre ailleurs ? )
452 if (dimension > 2)
453 {
454 const IntTab& elem_aretes = domaine().elem_aretes();
455 const IntTab& aretes_som = domaine().aretes_som();
456
457 int nb_faces = face_sommets_.dimension(0);
458 int nb_faces_tot = face_sommets_.dimension_tot(0);
459
460 int nb_edges_max = face_sommets_.dimension(1);
461 int nb_edges_elem_max = domaine().elem_aretes().dimension(1);
462
463 face_aretes_.resize(nb_faces,nb_edges_max);
464 creer_tableau_faces(face_aretes_, RESIZE_OPTIONS::NOCOPY_NOINIT);
465 face_aretes_ = -1;
466
467 int arete;
468 int node0, node1;
469
470 for (int f=0; f<nb_faces_tot; f++)
471 {
472 int i = 0;
473 int elem0 = face_voisins_(f,0);
474 int elem1 = face_voisins_(f,1);
475
476 int elem = (elem0 == -1 ? elem1 : elem0);
477
478 int last_index = nb_edges_max-1;
479 while (face_sommets_(f,last_index) == -1) last_index--;
480
481 for (int k=0; k<nb_edges_elem_max; k++)
482 {
483 arete = elem_aretes(elem,k);
484
485 if (arete == -1) break;
486 node0 = aretes_som(arete,0);
487 node1 = aretes_som(arete,1);
488
489 for (int j=0; j<nb_edges_max; j++)
490 {
491 // find continuous edge in face_nodes_
492 if (face_sommets_(f,j) == node0)
493 {
494 int previous = j > 0 ? j-1 : last_index;
495 int next = j < last_index ? j+1 : 0;
496
497 if (face_sommets_(f,previous) == node1 || face_sommets(f,next) == node1)
498 {
499 face_aretes_(f,i) = arete;
500 i++;
501 }
502 }
503 }
504 }
505 }
506 }
507}
508
510{
511 const IntTab& f_s = face_sommets(), &e_s = domaine().les_elems(), &e_f = elem_faces();
512 const DoubleTab& xs = domaine().coord_sommets(), &nf = face_normales_;
513 const DoubleVect& fs = face_surfaces();
514 int i, j, e, f, s, np;
515 DoubleTab M(0, dimension + 1), X(dimension + 1, 1), S(0, 1), vp; //pour les systemes lineaires
516
517 IntTrav b_f_ortho, b_e_ortho; // b_{f,e}_ortho(f/e) = 1 si la face / l'element est orthocentre
518 creer_tableau_faces(b_f_ortho), domaine().creer_tableau_elements(b_e_ortho);
519
520 /* 1. orthocentrage des faces (en dimension 3) */
521 Cerr << domaine().le_nom() << " : ";
522 if (dimension < 3) b_f_ortho = 1; //les faces (segments) sont deja orthcentrees!
523 else for (f = 0; f < nb_faces_tot(); f++)
524 {
525 //la face est-elle deja orthocentree?
526 double d2min = DBL_MAX, d2max = 0, d2;
527 for (i = 0, np = 0; i < f_s.dimension(1) && (s = f_s(f, i)) >= 0; i++, np++)
528 d2min = std::min(d2min, d2 = dot(&xs(s, 0), &xs(s, 0), &xv_(f, 0), &xv_(f, 0))), d2max = std::max(d2max, d2);
529 if ((b_f_ortho(f) = (d2max / d2min - 1 < 1e-8))) continue;
530
531 //peut-on l'orthocentrer?
532 M.resize(np + 1, 4), S.resize(np + 1, 1);
533 for (i = 0; i < np; i++)
534 for (j = 0, S(i, 0) = 0, M(i, 3) = 1; j < 3; j++)
535 S(i, 0) += 0.5 * std::pow(M(i, j) = xs(f_s(f, i), j) - xv_(f, j), 2);
536 for (j = 0, S(np, 0) = M(np, 3) = 0; j < 3; j++) M(np, j) = nf(f, j) / fs(f);
537 if (kersol(M, S, 1e-12, nullptr, X, vp) > 1e-8) continue; //la face n'a pas d'orthocentre
538
539 //contrainte : ne pas diminuer la distance entre xv et chaque arete de plus de 50%
540 double r2min = DBL_MAX;
541 for (i = 0; i < f_s.dimension(1) && (s = f_s(f, i)) >= 0; i++)
542 {
543 int s2 = f_s(f, i + 1 < f_s.dimension(1) && f_s(f, i + 1) >= 0 ? i + 1 : 0),
544 a = som_arete[s].at(s2);
545 std::array<double, 3> vec = cross(3, 3, &xv_(f, 0), &ta_(a, 0), &xs(s, 0));
546 r2min = std::min(r2min, dot(&vec[0], &vec[0]));
547 }
548 if (dot(&X(0, 0), &X(0, 0)) > 0.25 * r2min) continue; //on s'eloigne trop du CG
549
550 for (i = 0, b_f_ortho(f) = 1; i < dimension; i++)
551 if (std::fabs(X(i, 0)) > 1e-8) xv_(f, i) += X(i, 0);
552 }
553 Cerr << 100. * (double)(mp_somme_vect(b_f_ortho) / Process::mp_sum(nb_faces())) << "% orthocentered faces " << finl;
554
555 /* 2. orthocentrage des elements */
556 Cerr << domaine().le_nom() << " : ";
557 for (e = 0; e < nb_elem_tot(); e++)
558 {
559 //l'element est-il deja orthocentre?
560 double d2min = DBL_MAX, d2max = 0, d2;
561 for (i = 0, np = 0; i < e_s.dimension(1) && (s = e_s(e, i)) >= 0; i++, np++)
562 d2min = std::min(d2min, d2 = dot(&xs(s, 0), &xs(s, 0), &xp_(e, 0), &xp_(e, 0))), d2max = std::max(d2max, d2);
563 if ((b_e_ortho(e) = (d2max / d2min - 1 < 1e-8))) continue;
564
565 //pour qu'on puisse l'orthocentrer, il faut que ses faces le soient
566 for (i = 0, j = 1; i < e_f.dimension(1) && (f = e_f(e, i)) >= 0; i++) j = j && b_f_ortho(f);
567 if (!j) continue;
568
569 //existe-il un orthocentre?
570 M.resize(np, dimension + 1), S.resize(np, 1);
571 for (i = 0; i < np; i++)
572 for (j = 0, S(i, 0) = 0, M(i, dimension) = 1; j < dimension; j++)
573 S(i, 0) += 0.5 * std::pow(M(i, j) = xs(e_s(e, i), j) - xp_(e, j), 2);
574 if (kersol(M, S, 1e-12, nullptr, X, vp) > 1e-8) continue; //l'element n'a pas d'orthocentre
575
576 //contrainte : ne pas diminuer la distance entre xp et chaque face de plus de 50%
577 double rmin = DBL_MAX;
578 for (i = 0; i < e_f.dimension(1) && (f = e_f(e, i)) >= 0; i++)
579 rmin = std::min(rmin, std::fabs(dot(&xp_(e, 0), &nf(f, 0), &xv_(f, 0)) / fs(f)));
580 if (dot(&X(0, 0), &X(0, 0)) > 0.25 * rmin * rmin) continue; //on s'eloigne trop du CG
581
582 for (i = 0, b_e_ortho(e) = 1; i < dimension; i++)
583 if (std::fabs(X(i, 0)) > 1e-8) xp_(e, i) += X(i, 0);
584 }
585 Cerr << 100. * (double)(mp_somme_vect(b_e_ortho) / Process::mp_sum(nb_elem())) << "% d'elements orthocentres" << finl;
586}
587
589{
590 // Calcul de h_carre
591 h_carre = 1.e30;
592 if (h_carre_.size()) return; // deja fait
593 h_carre_.resize(nb_elem_tot());
594 // Calcul des surfaces
595 const DoubleVect& surfaces=face_surfaces();
596 const int nb_faces_elem=domaine().nb_faces_elem();
597 const int nbe=nb_elem_tot();
598 for (int num_elem=0; num_elem<nbe; num_elem++)
599 {
600 double surf_max = 0;
601 for (int i=0; i<nb_faces_elem; i++)
602 {
603 double surf = surfaces(elem_faces(num_elem,i));
604 surf_max = (surf > surf_max)? surf : surf_max;
605 }
606 double vol = volumes(num_elem)/surf_max;
607 vol *= vol;
608 h_carre_(num_elem) = vol;
609 h_carre = ( vol < h_carre )? vol : h_carre;
610 }
611}
612
613void disp_dt(const DoubleTab& A)
614{
615 int i, j, k, l;
616 if (A.nb_dim() == 4)
617 for (i = 0; i < A.dimension_tot(0); i++)
618 for (j = 0, fprintf(stderr, i ? "}}},{" : "{{"); j < A.dimension(1); j++)
619 for (k = 0, fprintf(stderr, j ? "}},{" : "{"); k < A.dimension(2); k++)
620 for (l = 0, fprintf(stderr, k ? "},{" : "{"); l < A.dimension(3); l++)
621 fprintf(stderr, "%.10E%s ", A.addr()[A.dimension(3) * (A.dimension(2) * (i * A.dimension(1) + j) + k) + l], l + 1 < A.dimension(3) ? "," : "");
622 else if (A.nb_dim() == 3)
623 for (i = 0; i < A.dimension_tot(0); i++)
624 for (j = 0, fprintf(stderr, i ? "}},{" : "{{"); j < A.dimension(1); j++)
625 for (k = 0, fprintf(stderr, j ? "},{" : "{"); k < A.dimension(2); k++)
626 fprintf(stderr, "%.10E%s ", A.addr()[A.dimension(2) * (i * A.dimension(1) + j) + k], k + 1 < A.dimension(2) ? "," : "");
627 else if (A.nb_dim() == 2)
628 for (i = 0; i < A.dimension_tot(0); i++)
629 for (j = 0, fprintf(stderr, i ? "},{" : "{{"); j < A.dimension(1); j++)
630 fprintf(stderr, "%.10E%s ", A.addr()[i * A.dimension(1) + j], j + 1 < A.dimension(1) ? "," : "");
631 else for (i = 0, fprintf(stderr, "{"); i < A.dimension_tot(0); i++)
632 fprintf(stderr, "%.10E%s ", A.addr()[i], i + 1 < A.dimension_tot(0) ? "," : "");
633 fprintf(stderr, A.nb_dim() == 4 ? "}}}}\n" : A.nb_dim() == 3 ? "}}}\n" : A.nb_dim() == 2 ? "}}\n" : "}\n");
634}
635
636void disp_da(const ArrOfDouble& A)
637{
638 int i;
639 for (i = 0, fprintf(stderr, "{"); i < A.size_array(); i++)
640 fprintf(stderr, "%.10E%s ", A.addr()[i], i + 1 < A.size_array() ? "," : "");
641 fprintf(stderr, "}\n");
642}
643
644void disp_it(const IntTab& A)
645{
646 int i, j, k, l;
647 if (A.nb_dim() == 4)
648 for (i = 0; i < A.dimension_tot(0); i++)
649 for (j = 0, fprintf(stderr, i ? "}}},{" : "{{"); j < A.dimension(1); j++)
650 for (k = 0, fprintf(stderr, j ? "}},{" : "{"); k < A.dimension(2); k++)
651 for (l = 0, fprintf(stderr, k ? "},{" : "{"); l < A.dimension(3); l++)
652 fprintf(stderr, "%d%s ", (int)A.addr()[A.dimension(3) * (A.dimension(2) * (i * A.dimension(1) + j) + k) + l], l + 1 < A.dimension(3) ? "," : "");
653 else if (A.nb_dim() == 3)
654 for (i = 0; i < A.dimension_tot(0); i++)
655 for (j = 0, fprintf(stderr, i ? "}},{" : "{{"); j < A.dimension(1); j++)
656 for (k = 0, fprintf(stderr, j ? "},{" : "{"); k < A.dimension(2); k++)
657 fprintf(stderr, "%d%s ", (int)A.addr()[A.dimension(2) * (i * A.dimension(1) + j) + k], k + 1 < A.dimension(2) ? "," : "");
658 else if (A.nb_dim() == 2)
659 for (i = 0; i < A.dimension_tot(0); i++)
660 for (j = 0, fprintf(stderr, i ? "},{" : "{{"); j < A.dimension(1); j++)
661 fprintf(stderr, "%d%s ", (int)A.addr()[i * A.dimension(1) + j], j + 1 < A.dimension(1) ? "," : "");
662 else for (i = 0, fprintf(stderr, "{"); i < A.dimension_tot(0); i++)
663 fprintf(stderr, "%d%s ", (int)A.addr()[i], i + 1 < A.dimension_tot(0) ? "," : "");
664 fprintf(stderr, A.nb_dim() == 4 ? "}}}}\n" : A.nb_dim() == 3 ? "}}}\n" : A.nb_dim() == 2 ? "}}\n" : "}\n");
665}
666
667void disp_ia(const ArrOfInt& A)
668{
669 int i;
670 for (i = 0, fprintf(stderr, "{"); i < A.size_array(); i++)
671 fprintf(stderr, "%d%s ", (int)A.addr()[i], i + 1 < A.size_array() ? "," : "");
672 fprintf(stderr, "}\n");
673}
674
675void disp_m(const Matrice_Base& M_in)
676{
679 DoubleTab A(M.nb_lignes(), M.nb_colonnes());
680 for (int i = 0; i < A.dimension(0); i++)
681 for (auto k = M.get_tab1().addr()[i] - 1; k < M.get_tab1().addr()[i + 1] - 1; k++)
682 A(i, M.get_tab2().addr()[k] - 1) = M.get_coeff().addr()[k];
683 disp_dt(A);
684}
685
686void disp_mt(const tabs_t& mvect)
687{
688 for (auto &&n_v : mvect)
689 fprintf(stderr, "%s:\n", n_v.first.c_str()), disp_dt(n_v.second), fprintf(stderr, "\n");
690}
691
692void disp_mm(const std::map<std::string, Matrice_Morse>& mmat)
693{
694 for (auto &&n_v : mmat)
695 fprintf(stderr, "%s:\n", n_v.first.c_str()), disp_m(n_v.second), fprintf(stderr, "\n");
696}
697
698void disp_mmp(const matrices_t& mmat)
699{
700 for (auto &&n_v : mmat)
701 fprintf(stderr, "%s:\n", n_v.first.c_str()), disp_m(*n_v.second), fprintf(stderr, "\n");
702}
703
704DoubleVect& Domaine_Poly_base::dist_norm_bord(DoubleVect& dist, const Nom& nom_bord) const
705{
706 for (int n_bord=0; n_bord<les_bords_.size(); n_bord++)
707 {
708 const Front_VF& fr_vf = front_VF(n_bord);
709 if (fr_vf.le_nom() == nom_bord)
710 {
711 dist.resize(fr_vf.nb_faces());
712 int ndeb = fr_vf.num_premiere_face();
713 for (int face=ndeb; face<ndeb+fr_vf.nb_faces(); face++)
714 dist(face-ndeb) = dist_norm_bord(face);
715 }
716 }
717 return dist;
718}
719
720const IntTab& Domaine_Poly_base::equiv() const
721{
722 if (equiv_.nb_dim() != 3) init_equiv();
723 return equiv_;
724}
725
726const Static_Int_Lists& Domaine_Poly_base::som_elem() const
727{
728 if (som_elem_.get_nb_lists() >= 0) return som_elem_;
729 construire_connectivite_som_elem(domaine().nb_som_tot(), domaine().les_elems(), som_elem_, 1);
730 return som_elem_;
731}
732
733const IntTab& Domaine_Poly_base::elem_som_d() const
734{
735 if (elem_som_d_.size()) return elem_som_d_;
736 const IntTab& e_s = domaine().les_elems();
737 elem_som_d_.resize(nb_elem_tot() + 1);
738 for (int e = 0, i; e < nb_elem_tot(); e++)
739 for (elem_som_d_(e + 1) = elem_som_d_(e), i = 0; i < e_s.dimension(1) && e_s(e, i) >= 0; i++)
740 elem_som_d_(e + 1)++;
741 return elem_som_d_;
742}
743
745{
746 if (elem_arete_d_.size()) return elem_arete_d_;
747 const IntTab& e_a = dimension < 3 ? elem_faces() : domaine().elem_aretes();
748 elem_arete_d_.resize(nb_elem_tot() + 1);
749 for (int e = 0, i; e < nb_elem_tot(); e++)
750 for (elem_arete_d_(e + 1) = elem_arete_d_(e), i = 0; i < e_a.dimension(1) && e_a(e, i) >= 0; i++)
751 elem_arete_d_(e + 1)++;
752 return elem_arete_d_;
753}
754
755const DoubleTab& Domaine_Poly_base::vol_elem_som() const
756{
757 if (vol_elem_som_.size()) return vol_elem_som_; //deja fait
758 const IntTab& es_d = elem_som_d(), &e_f = elem_faces(), &f_s = face_sommets(), &e_s = domaine().les_elems();
759 const DoubleTab& xs = domaine().coord_sommets();
760 DoubleTab& vol = vol_elem_som_;
761 vol.resize(es_d(nb_elem_tot()));
762 int e, s, f, i, j, k, D = dimension;
763 for (e = 0; e < nb_elem_tot(); e++)
764 for (i = 0; i < e_f.dimension(1) && (f = e_f(e, i)) >= 0; i++)
765 for (j = 0; j < f_s.dimension(1) && (s = f_s(f, j)) >= 0; j++)
766 {
767 int sb = D < 3 ? -1 : f_s(f, j + 1 < f_s.dimension(1) && f_s(f, j + 1) >= 0 ? j + 1 : 0); //sommet suivant sur l'arete (3D)
768 auto vec = cross(D, D, &xv_(f, 0), &xs(s, 0), &xp_(e, 0), &xp_(e, 0));
769 double x = std::abs(D < 3 ? vec[2] : dot(&xs(sb, 0), &vec[0], &xp_(e, 0))); //volume du parallelepipede
770 for (k = 0; k < D - 1; k++) //contribution au volume de s (2D) ou a ceux de s / sb (3D)
771 vol(es_d(e) + (int)(std::find(&e_s(e, 0), &e_s(e, 0) + es_d(e + 1) - es_d(e), k ? sb : s) - &e_s(e, 0))) += x / (D < 3 ? 2 : 12);
772 }
773 return vol;
774}
775
776const DoubleTab& Domaine_Poly_base::pvol_som(const DoubleVect& porosite_elem) const
777{
778 if (pvol_som_.size()) return pvol_som_; //deja fait
779 const IntTab& es_d = elem_som_d(), &e_s = domaine().les_elems();
780 const DoubleTab& v_es = vol_elem_som();
782 for (int e = 0; e < nb_elem_tot(); e++)
783 for (int i = 0, j = es_d(e); j < es_d(e + 1); i++, j++)
784 pvol_som_(e_s(e, i)) += porosite_elem(e) * v_es(j);
785 pvol_som_.echange_espace_virtuel();
786 return pvol_som_;
787}
788
790{
791 if (dimension < 3) return;
792 /* ordre canonique dans aretes_som */
793 IntTab& a_s = domaine().set_aretes_som(), &e_a = domaine().set_elem_aretes();
794 const DoubleTab& xs = domaine().coord_sommets();
795 std::map<std::array<double, 3>, int> xv_fsa;
796 for (int a = 0, i, j, s; a < a_s.dimension_tot(0); a++)
797 {
798 for (i = 0, j = 0, xv_fsa.clear(); i < a_s.dimension(1) && (s = a_s(a, i)) >= 0; i++) xv_fsa[ {{ xs(s, 0), xs(s, 1), xs(s, 2) }}] = s;
799 for (auto &&c_s : xv_fsa) a_s(a, j) = c_s.second, j++;
800 }
801
802 //remplissage de som_aretes
803 som_arete.resize(domaine().nb_som_tot());
804 for (int i = 0; i < a_s.dimension_tot(0); i++)
805 for (int j = 0; j < 2; j++) som_arete[a_s(i, j)][a_s(i, !j)] = i;
806
807 for (int i = 0, k; i < domaine().nb_aretes_tot(); i++)
808 {
809 int s1 = a_s(i, 0), s2 = a_s(i, 1);
810 longueur_aretes_(i) = sqrt( dot(&xs(s2, 0), &xs(s2, 0), &xs(s1, 0), &xs(s1, 0)));
811 for (k = 0; k < 3; k++) xa_(i, k) = (xs(s1, k) + xs(s2, k)) / 2, ta_(i, k) = (xs(s2, k) - xs(s1, k)) / longueur_aretes_(i);
812 }
813
814 /* ordre canonique dans elem_aretes_ */
815 for (int e = 0, i, j, a; e < nb_elem_tot(); e++)
816 {
817 for (i = 0, j = 0, xv_fsa.clear(); i < e_a.dimension(1) && (a = e_a(e, i)) >= 0; i++) xv_fsa[ {{ xa_(a, 0), xa_(a, 1), xa_(a, 2) }}] = a;
818 for (auto &&c_a : xv_fsa) e_a(e, j) = c_a.second, j++;
819 }
820}
821
823{
824 if (dimension < 3) return;
825 /* recalcul de xv pour avoir les vrais CG des faces */
826 const DoubleTab& coords = domaine().coord_sommets();
827 for (int face = 0; face < nb_faces(); face++)
828 {
829 double xs[3] = { 0, }, S = 0;
830 for (int k = 0; k < face_sommets_.dimension(1); k++)
831 if (face_sommets_(face, k) >= 0)
832 {
833 int s0 = face_sommets_(face, 0), s1 = face_sommets_(face, k),
834 s2 = k + 1 < face_sommets_.dimension(1) && face_sommets_(face, k + 1) >= 0 ? face_sommets_(face, k +1) : s0;
835 double s = 0;
836 for (int r = 0; r < 3; r++)
837 for (int i = 0; i < 2; i++)
838 s += (i ? -1 : 1) * face_normales_(face, r) * (coords(s2, (r + 1 + i) % 3) - coords(s0, (r + 1 + i) % 3))
839 * (coords(s1, (r + 1 + !i) % 3) - coords(s0, (r + 1 + !i) % 3));
840 for (int r = 0; r < 3; r++) xs[r] += s * (coords(s0, r) + coords(s1, r) + coords(s2, r)) / 3;
841 S += s;
842 }
843 if (S == 0 && sub_type(Hexa_poly,type_elem_.valeur()))
844 {
845 Cerr << "===============================" << finl;
846 Cerr << "Error in your mesh for " << que_suis_je() << "!" << finl;
847 Cerr << "Add this keyword before discretization in your data file to create polyedras:" << finl;
848 Cerr << "Polyedriser " << domaine().le_nom() << finl;
850 }
851 for (int r = 0; r < 3; r++) xv_(face, r) = xs[r] / S;
852 }
853 xv_.echange_espace_virtuel();
854
855}
classe Cond_lim_base Classe de base pour la hierarchie des classes qui representent les differentes c...
virtual Frontiere_dis_base & frontiere_dis()
Renvoie la frontiere discretisee a laquelle les conditions aux limites s'appliquent.
classe Conds_lim Cette classe represente un vecteur de conditions aux limites.
Definition Conds_lim.h:32
int_t nb_aretes_tot() const
renvoie le nombre d'aretes total (reelles+virtuelles).
Definition Domaine.h:145
void creer_aretes()
Definition Domaine.cpp:2122
const IntTab_t & aretes_som() const
renvoie le tableau de connectivite aretes/sommets.
Definition Domaine.h:156
virtual void creer_tableau_elements(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
creation d'un tableau parallele de valeurs aux elements.
Definition Domaine.cpp:851
IntTab_t & set_aretes_som()
Definition Domaine.h:159
IntTab_t & set_elem_aretes()
Definition Domaine.h:160
IntTab_t & les_elems()
Definition Domaine.h:129
int nb_faces_elem(int=0) const
Renvoie le nombre de face de type i des elements geometriques constituants le domaine.
Definition Domaine.h:484
void typer(const Nom &)
Type les elements du domaine avec le nom passe en parametre.
Definition Domaine.h:457
const DoubleTab_t & coord_sommets() const
Definition Domaine.h:112
virtual void creer_tableau_sommets(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
Cree un tableau ayant une "ligne" par sommet du maillage.
Definition Domaine.cpp:1000
int_t elem_aretes(int_t i, int j) const
renvoie le numero de la jeme arete du ieme element.
Definition Domaine.h:154
class Domaine_Poly_base
void detecter_faces_non_planes() const
const DoubleTab & vol_elem_som() const
virtual void calculer_volumes_entrelaces()
void modifier_pour_Cl(const Conds_lim &) override
void verifier_type_elem() const
const Static_Int_Lists & som_elem() const
const IntTab & elem_som_d() const
virtual void init_equiv() const =0
const IntTab & equiv() const
std::vector< std::map< int, int > > som_arete
void discretiser() override
const DoubleTab & pvol_som(const DoubleVect &poro) const
virtual void calculer_h_carre()
Static_Int_Lists som_elem_
double dist_norm_bord(int num_face) const override
void corriger_face_voisins_sur_les_faces_virtuelles()
const IntTab & elem_arete_d() const
Sortie & ecrit(Sortie &os) const
void typer_elem(Domaine &domaine_geom) override
class Domaine_VF
Definition Domaine_VF.h:44
IntVect rang_elem_non_std_
Definition Domaine_VF.h:252
void creer_tableau_aretes(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
virtual const DoubleVect & face_surfaces() const
Definition Domaine_VF.h:51
int nb_faces() const
renvoie le nombre global de faces.
Definition Domaine_VF.h:471
DoubleTab xp_
Definition Domaine_VF.h:218
IntTab & face_sommets() override
renvoie le tableau de connectivite faces/sommets.
Definition Domaine_VF.h:591
DoubleVect volumes_entrelaces_
Definition Domaine_VF.h:210
const MD_Vector & md_vector_faces() const
Definition Domaine_VF.h:158
const MD_Vector & md_vector_aretes() const
Definition Domaine_VF.h:160
DoubleTab xa_
Definition Domaine_VF.h:225
int nb_faces_tot() const
renvoie le nombre total de faces.
Definition Domaine_VF.h:481
double dot(const double *a, const double *b, const double *ma=nullptr, const double *mb=nullptr) const
Definition Domaine_VF.h:696
void creer_tableau_faces(Array_base &, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT) const
DoubleTab xv_
Definition Domaine_VF.h:219
int nb_elem_std_
Definition Domaine_VF.h:250
IntTab face_sommets_
Definition Domaine_VF.h:223
int nb_faces_std_
Definition Domaine_VF.h:251
void discretiser() override
Genere les faces construits les frontieres.
IntTab & elem_faces()
renvoie le tableau de connectivite element/faces
Definition Domaine_VF.h:551
DoubleVect volumes_
Definition Domaine_VF.h:208
IntTab face_voisins_
Definition Domaine_VF.h:216
IntTab elem_faces_
Definition Domaine_VF.h:222
IntTab face_aretes_
Definition Domaine_VF.h:224
DoubleVect & volumes()
Definition Domaine_VF.h:119
std::array< double, 3 > cross(int dima, int dimb, const double *a, const double *b, const double *ma=nullptr, const double *mb=nullptr) const
Definition Domaine_VF.h:711
DoubleTab face_normales_
Definition Domaine_VF.h:212
MD_Vector md_vector_aretes_
Definition Domaine_VF.h:233
DoubleTab volumes_entrelaces_dir_
Definition Domaine_VF.h:211
const Front_VF & front_VF(int i) const
Definition Domaine_VF.h:112
IntTab & face_voisins() override
renvoie le tableaux des volumes des connectivites face elements cf au dessus.
Definition Domaine_VF.h:426
void marquer_faces_double_contrib(const Conds_lim &)
const Nom & le_nom() const override
Donne le nom de l'Objet_U Methode a surcharger : renvoie "neant" dans cette implementation.
int nb_elem_tot() const
const Domaine & domaine() const
int nb_som_tot() const
Class defining operators and methods for all reading operation in an input flow (file,...
Definition Entree.h:42
class Front_VF
Definition Front_VF.h:36
int nb_faces() const
Definition Front_VF.h:53
int num_premiere_face() const
Definition Front_VF.h:63
int nb_faces_tot() const
Definition Front_VF.h:58
int num_face(const int) const
Definition Front_VF.h:68
const Nom & le_nom() const override
Renvoie le nom de la frontiere geometrique.
Metadata for a distributed composite vector.
void add_part(const MD_Vector &part, int shape=0, Nom name="")
Append the "part" descriptor to the composite vector.
Classe Matrice_Base Classe de base de la hierarchie des matrices.
Classe Matrice_Morse Represente une matrice M (creuse), non necessairement carree.
const auto & get_tab2() const
const auto & get_tab1() const
int nb_colonnes() const override
Return local number of columns (=size on the current proc).
const auto & get_coeff() const
int nb_lignes() const override
Return local number of lines (=size on the current proc).
static void convert_to_morse_matrix(const Matrice_Base &in, Matrice_Morse &out)
class Nom Une chaine de caractere pour nommer les objets de TRUST
Definition Nom.h:31
static int dimension
Definition Objet_U.h:99
friend class Sortie
Definition Objet_U.h:75
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
virtual Sortie & printOn(Sortie &) const
Ecriture de l'objet sur un flot de sortie Methode a surcharger.
Definition Objet_U.cpp:282
classe Periodique Cette classe represente une condition aux limites periodique.
Definition Periodique.h:31
int face_associee(int i) const
Definition Periodique.h:35
static Sortie & Journal(int message_level=0)
Renvoie un objet statique de type Sortie qui sert de journal d'evenements.
Definition Process.cpp:588
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 double mp_sum(double)
Calcule la somme de x sur tous les processeurs du groupe courant.
Definition Process.cpp:146
static int me()
renvoie mon rang dans le groupe de communication courant.
Definition Process.cpp:125
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
_TYPE_ * addr()
int nb_dim() const
Definition TRUSTTab.h:199
void resize(_SIZE_ n, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTTab.tpp:469
_SIZE_ dimension_tot(int) const override
Definition TRUSTTab.tpp:160
_SIZE_ dimension(int d) const
Definition TRUSTTab.tpp:133
void resize(_SIZE_, RESIZE_OPTIONS opt=RESIZE_OPTIONS::COPY_INIT)
Definition TRUSTVect.tpp:91
virtual const MD_Vector & get_md_vector() const
Definition TRUSTVect.h:123