Arcane  v3.16.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
CartesianMeshTesterModule.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2024 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* CartesianMeshTesterModule.cc (C) 2000-2024 */
9/* */
10/* Module de test du gestionnaire de maillages cartésiens. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/CheckedConvert.h"
15#include "arcane/utils/PlatformUtils.h"
16#include "arcane/utils/StringBuilder.h"
17
20
21#include "arcane/core/ITimeLoopMng.h"
22#include "arcane/core/ITimeLoopService.h"
23#include "arcane/core/ITimeLoop.h"
24#include "arcane/core/TimeLoopEntryPointInfo.h"
25#include "arcane/core/IMesh.h"
26#include "arcane/core/IItemFamily.h"
27#include "arcane/core/ItemPrinter.h"
28#include "arcane/core/IParallelMng.h"
29#include "arcane/core/IMeshWriter.h"
30#include "arcane/core/MeshKind.h"
31
32#include "arcane/core/ICaseDocument.h"
33#include "arcane/core/IInitialPartitioner.h"
34#include "arcane/core/IMesh.h"
35#include "arcane/core/IItemFamily.h"
36#include "arcane/core/IMeshModifier.h"
37#include "arcane/core/IMeshUtilities.h"
38#include "arcane/core/ServiceBuilder.h"
40#include "arcane/core/IMeshPartitionerBase.h"
41#include "arcane/core/BasicService.h"
42#include "arcane/core/MeshReaderMng.h"
43#include "arcane/core/IGridMeshPartitioner.h"
44#include "arcane/core/ICartesianMeshGenerationInfo.h"
45#include "arcane/core/AbstractItemOperationByBasicType.h"
46
47#include "arcane/core/Connectivity.h"
48
49#include "arcane/cartesianmesh/CartesianMeshCoarsening.h"
50#include "arcane/cartesianmesh/CartesianMeshCoarsening2.h"
51
52#include "arcane/cartesianmesh/CartesianMeshUtils.h"
53#include "arcane/cartesianmesh/ICartesianMesh.h"
54#include "arcane/cartesianmesh/CellDirectionMng.h"
55#include "arcane/cartesianmesh/NodeDirectionMng.h"
56#include "arcane/cartesianmesh/CartesianConnectivity.h"
57
58#include "arcane/cartesianmesh/ICartesianMeshPatch.h"
59
60#include "arcane/tests/ArcaneTestGlobal.h"
61#include "arcane/tests/CartesianMeshTester_axl.h"
62#include "arcane/tests/CartesianMeshTestUtils.h"
63#include "arcane/tests/CartesianMeshV2TestUtils.h"
64
65/*---------------------------------------------------------------------------*/
66/*---------------------------------------------------------------------------*/
67
68namespace ArcaneTest
69{
70
71using namespace Arcane;
72
73/*---------------------------------------------------------------------------*/
74/*---------------------------------------------------------------------------*/
78class CartesianMeshTesterModule
79: public ArcaneCartesianMeshTesterObject
80{
83 {
84 public:
85
86 void applyQuad4(ItemVectorView group) override { m_nb_quad4 += group.size(); }
87 void applyHexaedron8(ItemVectorView group) override { m_nb_hexa8 += group.size(); }
88
89 public:
90
91 Int32 m_nb_quad4 = 0;
92 Int32 m_nb_hexa8 = 0;
93 };
94
95 public:
96
97 explicit CartesianMeshTesterModule(const ModuleBuildInfo& mbi);
98 ~CartesianMeshTesterModule();
99
100 public:
101
102 static void staticInitialize(ISubDomain* sd);
103
104 public:
105
106 void buildInit() override;
107 void compute() override;
108 void init() override;
109
110 private:
111
112 VariableCellReal m_density;
113 VariableCellReal m_old_density;
114 VariableCellReal3 m_cell_center;
115 VariableFaceReal3 m_face_center;
116 VariableNodeReal m_node_density;
117 VariableFaceInt64 m_faces_uid;
118 ICartesianMesh* m_cartesian_mesh;
119 IInitialPartitioner* m_initial_partitioner;
122
123 private:
124
125 void _compute1();
126 void _compute2();
127 void _sample(ICartesianMesh* cartesian_mesh);
128 void _testXmlInfos();
130 void _printCartesianMeshInfos();
131 void _checkFaceUniqueIdsAreContiguous();
132 void _checkNearlyEqual(Real3 a,Real3 b,const String& message);
133 void _testCoarsening();
134 void _checkSpecificApplyOperator();
135};
136
137/*---------------------------------------------------------------------------*/
138/*---------------------------------------------------------------------------*/
139
140class CartesianMeshPartitionerService
141: public BasicService
143{
144 public:
145 explicit CartesianMeshPartitionerService(const ServiceBuildInfo& sbi)
146 : BasicService(sbi){}
147 public:
148 void build() override {}
149 void notifyEndPartition() override {}
150 IPrimaryMesh* primaryMesh() override { return mesh()->toPrimaryMesh(); }
151 void partitionMesh(bool initial_partition) override
152 {
153 if (!initial_partition)
154 return;
155 IMesh* mesh = this->mesh();
156 IParallelMng* pm = mesh->parallelMng();
157 Int32 nb_rank = pm->commSize();
158 IItemFamily* cell_family = mesh->cellFamily();
159 VariableItemInt32& cells_new_owner = cell_family->itemsNewOwner();
160 ItemGroup own_cells = cell_family->allItems().own();
161 Int64 nb_cell = own_cells.size();
162 Int64 nb_bloc = nb_rank * 3;
163 Int64 cell_index = 0;
164 info() << "Partitioning with 'CartesianMeshPartitionerService' nb_rank=" << nb_rank;
165 ENUMERATE_CELL(icell,mesh->ownCells()){
166 Cell cell = *icell;
167 // Utilise des Int64 plutôt que des Int32 pour être sur de ne pas déborder.
168 Int64 new_owner = ((cell_index * nb_bloc) / nb_cell) % nb_rank;
169 cells_new_owner[cell] = CheckedConvert::toInt32(new_owner);
170 ++cell_index;
171 }
172 cells_new_owner.synchronize();
173 mesh->utilities()->changeOwnersFromCells();
174 }
175};
176
177/*---------------------------------------------------------------------------*/
178/*---------------------------------------------------------------------------*/
179
180ARCANE_REGISTER_SERVICE(CartesianMeshPartitionerService,
181 Arcane::ServiceProperty("CartesianMeshPartitionerTester",Arcane::ST_SubDomain),
183
184/*---------------------------------------------------------------------------*/
185/*---------------------------------------------------------------------------*/
186
187class CartesianMeshInitialPartitioner
188: public TraceAccessor
189, public IInitialPartitioner
190{
191 public:
192
193 CartesianMeshInitialPartitioner(ISubDomain* sd)
194 : TraceAccessor(sd->traceMng()), m_sub_domain(sd)
195 {
196 }
197 void build() override {}
199 {
200 for( IMesh* mesh : meshes ){
201 info() << "Partitioning mesh name=" << mesh->name();
202 _doPartition(mesh);
203 }
204 }
205 private:
206 void _doPartition(IMesh* mesh)
207 {
208 ServiceBuilder<IMeshPartitionerBase> sbuilder(m_sub_domain);
209 String service_name = "CartesianMeshPartitionerTester";
210 auto mesh_partitioner(sbuilder.createReference(service_name,mesh));
211
212 bool is_dynamic = mesh->isDynamic();
213 mesh->modifier()->setDynamic(true);
214 mesh->utilities()->partitionAndExchangeMeshWithReplication(mesh_partitioner.get(),true);
215 mesh->modifier()->setDynamic(is_dynamic);
216 }
217 private:
218 ISubDomain* m_sub_domain;
219};
220
221/*---------------------------------------------------------------------------*/
222/*---------------------------------------------------------------------------*/
223
224/*---------------------------------------------------------------------------*/
225/*---------------------------------------------------------------------------*/
226
227CartesianMeshTesterModule::
228CartesianMeshTesterModule(const ModuleBuildInfo& mbi)
229: ArcaneCartesianMeshTesterObject(mbi)
230, m_density(VariableBuildInfo(this,"Density"))
231, m_old_density(VariableBuildInfo(this,"OldDensity"))
232, m_cell_center(VariableBuildInfo(this,"CellCenter"))
233, m_face_center(VariableBuildInfo(this,"FaceCenter"))
234, m_node_density(VariableBuildInfo(this,"NodeDensity"))
235, m_faces_uid(VariableBuildInfo(this,"CartesianMeshTesterNodeUid"))
236, m_cartesian_mesh(nullptr)
237, m_initial_partitioner(nullptr)
238{
239 // Regarde s'il faut tester le partitionnement
240 if (!platform::getEnvironmentVariable("TEST_PARTITIONING").null()){
241 ISubDomain* sd = mbi.subDomain();
242 m_initial_partitioner = new CartesianMeshInitialPartitioner(sd);
243 info() << "SETTING INITIAL PARTITIONER";
244 // NOTE: le sous-domaine prend possession du partitionneur. Il ne faut
245 // donc pas le détruire.
246 sd->setInitialPartitioner(m_initial_partitioner);
247 }
248}
249
250/*---------------------------------------------------------------------------*/
251/*---------------------------------------------------------------------------*/
252
253CartesianMeshTesterModule::
254~CartesianMeshTesterModule()
255{
256}
257
258/*---------------------------------------------------------------------------*/
259/*---------------------------------------------------------------------------*/
260
261void CartesianMeshTesterModule::
262staticInitialize(ISubDomain* sd)
263{
264 String time_loop_name("CartesianMeshTestLoop");
265
266 ITimeLoopMng* tlm = sd->timeLoopMng();
267 ITimeLoop* time_loop = tlm->createTimeLoop(time_loop_name);
268
269 {
270 List<TimeLoopEntryPointInfo> clist;
271 clist.add(TimeLoopEntryPointInfo("CartesianMeshTester.buildInit"));
272 time_loop->setEntryPoints(ITimeLoop::WBuild,clist);
273 }
274
275 {
276 List<TimeLoopEntryPointInfo> clist;
277 clist.add(TimeLoopEntryPointInfo("CartesianMeshTester.init"));
278 time_loop->setEntryPoints(ITimeLoop::WInit,clist);
279 }
280
281 {
282 List<TimeLoopEntryPointInfo> clist;
283 clist.add(TimeLoopEntryPointInfo("CartesianMeshTester.compute"));
284 time_loop->setEntryPoints(ITimeLoop::WComputeLoop,clist);
285 }
286
287 {
288 StringList clist;
289 clist.add("CartesianMeshTester");
290 time_loop->setRequiredModulesName(clist);
291 clist.clear();
292 clist.add("ArcanePostProcessing");
293 clist.add("ArcaneCheckpoint");
294 time_loop->setOptionalModulesName(clist);
295 }
296
297 tlm->registerTimeLoop(time_loop);
298}
299
300/*---------------------------------------------------------------------------*/
301/*---------------------------------------------------------------------------*/
302
303void CartesianMeshTesterModule::
304buildInit()
305{
306 bool has_edge = options()->hasEdges();
307 info() << "Adding edge connectivity?=" << has_edge;
308 if (has_edge){
309 Connectivity c(mesh()->connectivity());
310 c.enableConnectivity(Connectivity::CT_HasEdge);
311 }
312
313 m_global_deltat.assign(1.0);
314
315 IItemFamily* cell_family = defaultMesh()->cellFamily();
316 cell_family->createGroup("CELL0");
317 cell_family->createGroup("CELL1");
318 cell_family->createGroup("CELL2");
319 IItemFamily* face_family = defaultMesh()->faceFamily();
320 face_family->createGroup("FACE0");
321 face_family->createGroup("FACE1");
322 face_family->createGroup("FACE2");
323 face_family->createGroup("FACE3");
324 face_family->createGroup("FACE4");
325 face_family->createGroup("FACE5");
326
327 face_family->createGroup("AllFacesDirection0");
328 face_family->createGroup("AllFacesDirection1");
329}
330
331/*---------------------------------------------------------------------------*/
332/*---------------------------------------------------------------------------*/
333
334void CartesianMeshTesterModule::
335init()
336{
337 IMesh* mesh = defaultMesh();
338
339 IItemFamily* cell_family = mesh->cellFamily();
340 Int32UniqueArray ids(1);
341 ids[0] = 0;
342 cell_family->createGroup("CELL0",ids,true);
343 ids[0] = 1;
344 cell_family->createGroup("CELL1",ids,true);
345 ids[0] = 2;
346 cell_family->createGroup("CELL2",ids,true);
347 IItemFamily* face_family = defaultMesh()->faceFamily();
348 ids[0] = 0;
349 face_family->createGroup("FACE0",ids,true);
350 ids[0] = 1;
351 face_family->createGroup("FACE1",ids,true);
352 ids[0] = 2;
353 face_family->createGroup("FACE2",ids,true);
354 ids[0] = 3;
355 face_family->createGroup("FACE3",ids,true);
356 ids[0] = 4;
357 face_family->createGroup("FACE4",ids,true);
358 ids[0] = 5;
359 face_family->createGroup("FACE5",ids,true);
360
361 // Calcule le centre des mailles
362 {
363 VariableNodeReal3& nodes_coord = mesh->nodesCoordinates();
364 ENUMERATE_CELL(icell,allCells()){
365 Cell cell = *icell;
366 Real3 center;
367 for( NodeLocalId inode : cell.nodeIds() )
368 center += nodes_coord[inode];
369 center /= cell.nbNode();
370 m_cell_center[icell] = center;
371 }
372 }
373
374 // Calcule le centre des faces
375 {
376 VariableNodeReal3& nodes_coord = mesh->nodesCoordinates();
377 ENUMERATE_FACE(iface,allFaces()){
378 Face face = *iface;
379 Real3 center;
380 for( NodeLocalId inode : face.nodeIds() )
381 center += nodes_coord[inode];
382 center /= face.nbNode();
383 m_face_center[iface] = center;
384 }
385 }
386
387 m_cartesian_mesh = ICartesianMesh::getReference(mesh);
388 m_cartesian_mesh->computeDirections();
389
390 m_utils = makeRef(new CartesianMeshTestUtils(m_cartesian_mesh,acceleratorMng()));
391 m_utils_v2 = makeRef(new CartesianMeshV2TestUtils(m_cartesian_mesh));
392
393 // Initialise la densité.
394 // On met une densité de 1.0 à l'intérieur
395 // et on ajoute une densité de 5.0 pour chaque direction dans les
396 // mailles de bord.
397 m_density.fill(1.0);
398 Integer nb_dir = defaultMesh()->dimension();
399 for( Integer idir=0; idir<nb_dir; ++idir){
400 CellDirectionMng cdm(m_cartesian_mesh->cellDirection(idir));
401 Integer nb_boundary1 = 0;
402 Integer nb_boundary2 = 0;
403 ENUMERATE_CELL(icell,cdm.innerCells()){
404 DirCell cc(cdm.cell(*icell));
405 Cell next = cc.next();
406 Cell prev = cc.previous();
407 if (next.null() || prev.null()){
408 // Maille au bord. J'ajoute de la densité.
409 // Ne devrait pas arriver car on est sur les innerCells()
410 ++nb_boundary1;
411 m_density[icell] += 5.0;
412 }
413 }
414 // Parcours les mailles frontières pour la direction
415 ENUMERATE_CELL(icell,cdm.outerCells()){
416 DirCell cc(cdm[icell]);
417 if (icell.index()<5)
418 info() << "CELL: cell=" << ItemPrinter(*icell)
419 << " next=" << ItemPrinter(cc.next())
420 << " previous=" << ItemPrinter(cc.previous());
421 // Maille au bord. J'ajoute de la densité.
422 ++nb_boundary2;
423 m_density[icell] += 5.0;
424 }
425
426 info() << "NB_BOUNDARY1=" << nb_boundary1 << " NB_BOUNDARY2=" << nb_boundary2;
427 }
428
429 m_utils->testAll(false);
430 m_utils_v2->testAll();
431 _checkFaceUniqueIdsAreContiguous();
432 _testXmlInfos();
434 _printCartesianMeshInfos();
435 _checkSpecificApplyOperator();
436}
437
438/*---------------------------------------------------------------------------*/
439/*---------------------------------------------------------------------------*/
440
441void CartesianMeshTesterModule::
442_testCoarsening()
443{
444 Int32 coarse_version = options()->coarseCartesianMesh();
445 IMesh* mesh = m_cartesian_mesh->mesh();
446 Int32 mesh_dim = mesh->dimension();
447 const Int32 coarse_factor = 1 << mesh_dim;
448 if (coarse_version==1){
449 info() << "Test CartesianCoarsening V1";
450 Ref<CartesianMeshCoarsening> coarser = m_cartesian_mesh->createCartesianMeshCoarsening();
451 IItemFamily* cell_family = mesh->cellFamily();
452 CellInfoListView cells(cell_family);
453 coarser->createCoarseCells();
454 Int32 index = 0;
455 for( Int32 cell_lid : coarser->coarseCells()){
456 Cell cell = cells[cell_lid];
457 info() << "Test1: CoarseCell= " << ItemPrinter(cell);
458 ConstArrayView<Int32> sub_cells(coarser->refinedCells(index));
459 ++index;
460 for( Int32 sub_lid : sub_cells )
461 info() << "SubCell=" << ItemPrinter(cells[sub_lid]);
462 }
463 coarser->removeRefinedCells();
464 }
465
466 if (coarse_version==2){
467 info() << "Test CartesianCoarsening V2";
468 const Int32 nb_orig_cell = ownCells().size();
469 Ref<CartesianMeshCoarsening2> coarser = CartesianMeshUtils::createCartesianMeshCoarsening2(m_cartesian_mesh);
470 coarser->createCoarseCells();
471 ENUMERATE_(Cell,icell,allCells()){
472 Cell cell = *icell;
473 if (cell.level()!=0)
474 continue;
475 info() << "Test2: CoarseCell= " << ItemPrinter(cell);
476 for( Int32 i=0, n=cell.nbHChildren(); i<n; ++i ){
477 info() << "SubCell=" << ItemPrinter(cell.hChild(i));
478 }
479 }
480 Int32 nb_patch = m_cartesian_mesh->nbPatch();
481 info() << "NB_PATCH=" << nb_patch;
482 for( Int32 i=0; i<nb_patch; ++i ){
483 ICartesianMeshPatch* p = m_cartesian_mesh->patch(i);
484 info() << "Patch i=" << i << " nb_cell=" << p->cells().size();
485 }
486 coarser->removeRefinedCells();
487 // Le nombre de mailles doit être égal au nombre d'origine
488 // divisé par \a coarse_factor.
489 const Int32 nb_final_cell = ownCells().size();
490 info() << "nb_orig_cell=" << nb_orig_cell << " nb_final_cell=" << nb_final_cell
491 << " coarse_factor=" << coarse_factor;
492 const Int32 nb_computed = nb_final_cell * coarse_factor;
493 if (nb_computed != nb_orig_cell)
494 ARCANE_FATAL("Bad number of cells orig={0} computed={1}", nb_orig_cell, nb_computed);
495 }
496}
497
498/*---------------------------------------------------------------------------*/
499/*---------------------------------------------------------------------------*/
500
501void CartesianMeshTesterModule::
502compute()
503{
504 if (m_global_iteration()==1)
505 _testCoarsening();
506
507 _compute1();
508}
509
510/*---------------------------------------------------------------------------*/
511/*---------------------------------------------------------------------------*/
512
513void CartesianMeshTesterModule::
514_compute1()
515{
516 // Pour test, on parcours les N directions
517 // et pour chaque maille, on modifie sa densité
518 // par la formule new_density = (density+density_next+density_prev) / 3.0.
519
520 // Effectue l'operation en deux fois. Une premiere sur les
521 // mailles internes, et une deuxieme sur les mailles externes.
522 // Du coup, il faut passer par une variable intermediaire (m_old_density)
523 // mais on evite un test dans la boucle principale
524 Integer nb_dir = defaultMesh()->dimension();
525 for( Integer idir=0; idir<nb_dir; ++idir){
526 m_old_density.copy(m_density);
527 CellDirectionMng cdm(m_cartesian_mesh->cellDirection(idir));
528 // Travail sur les mailles internes
529 ENUMERATE_CELL(icell,cdm.innerCells()){
530 DirCell cc(cdm.cell(*icell));
531 Cell next = cc.next();
532 Cell prev = cc.previous();
533 Real d = m_old_density[icell] + m_old_density[next] + m_old_density[prev];
534 m_density[icell] = d / 3.0;
535 }
536 // Travail sur les mailles externes
537 // Test si la maille avant ou apres est nulle.
538 ENUMERATE_CELL(icell,cdm.outerCells()){
539 DirCell cc(cdm[icell]);
540 Cell next = cc.next();
541 Cell prev = cc.previous();
542 Real d = m_old_density[icell];
543 Integer n = 1;
544 if (!next.null()){
545 d += m_old_density[next];
546 ++n;
547 }
548 if (!prev.null()){
549 d += m_old_density[prev];
550 ++n;
551 }
552 m_density[icell] = d / n;
553 }
554 }
555
556 {
557 Int64 to_add = m_global_iteration();
558 ENUMERATE_(Face,iface,ownFaces()){
559 Int64 uid = iface->uniqueId();
560 m_faces_uid[iface] = uid + to_add;
561 }
562 m_faces_uid.synchronize();
563 ENUMERATE_(Face,iface,allFaces()){
564 Face face(*iface);
565 Int64 uid = face.uniqueId();
566 Int64 expected_value = uid + to_add;
567 if (expected_value!=m_faces_uid[iface])
568 ARCANE_FATAL("Bad FaceUid face={0} expected={1} value={2}",ItemPrinter(face),expected_value,m_faces_uid[iface]);
569 }
570 }
571}
572
573/*---------------------------------------------------------------------------*/
574/*---------------------------------------------------------------------------*/
575
576void CartesianMeshTesterModule::
577_compute2()
578{
579 // Pour test, on parcours les N directions
580 // et pour chaque maille, on modifie sa densité
581 // par la formule new_density = (density+density_next+density_prev) / 3.0.
582
583 // A noter que cette methode ne donne pas le meme comportement que
584 // _compute1() car les mailles de bord et internes sont mises à jour
585 // dans un ordre différent.
586 Integer nb_dir = defaultMesh()->dimension();
587 for( Integer idir=0; idir<nb_dir; ++idir){
588 CellDirectionMng cdm(m_cartesian_mesh->cellDirection(idir));
589 // Travail sur toutes les mailles
590 ENUMERATE_CELL(icell,cdm.allCells()){
591 DirCell cc(cdm[icell]);
592 Cell next = cc.next();
593 Cell prev = cc.previous();
594 Real d = m_density[icell];
595 Integer n = 1;
596 if (!next.null()){
597 d += m_density[next];
598 ++n;
599 }
600 if (!prev.null()){
601 d += m_density[prev];
602 ++n;
603 }
604 m_density[icell] = d / n;
605 }
606 }
607}
608
609/*---------------------------------------------------------------------------*/
610/*---------------------------------------------------------------------------*/
611
613_sample(ICartesianMesh* cartesian_mesh)
614{
616 CartesianConnectivity cc = cartesian_mesh->connectivity();
617 ENUMERATE_NODE(inode,allNodes()){
618 Node n = *inode;
619 Cell c1 = cc.upperLeft(n); // Maille en haut à gauche
620 Cell c2 = cc.upperRight(n); // Maille en haut à droite
621 Cell c3 = cc.lowerRight(n); // Maille en bas à droite
622 Cell c4 = cc.lowerLeft(n); // Maille en bas à gauche
623 info(6) << " C1=" << ItemPrinter(c1) << " C2=" << ItemPrinter(c2)
624 << " C3=" << ItemPrinter(c3) << " C4=" << ItemPrinter(c4);
625 }
627}
628
629/*---------------------------------------------------------------------------*/
630/*---------------------------------------------------------------------------*/
631
632void CartesianMeshTesterModule::
633_checkFaceUniqueIdsAreContiguous()
634{
635 if (!options()->checkContiguousFaceUniqueIds())
636 return;
637 info() << "Test " << A_FUNCINFO;
638 // Parcours les faces et vérifie que le uniqueId() de chaque face n'est
639 // pas supérieur au nombre total de face.
640 Int64 total_nb_face = allFaces().own().size();
641 total_nb_face = parallelMng()->reduce(Parallel::ReduceSum,total_nb_face);
642 info() << "TotalNbFace=" << total_nb_face;
643 ENUMERATE_(Face,iface,allFaces()){
644 Face face = *iface;
645 if (face.uniqueId()>=total_nb_face)
646 ARCANE_FATAL("FaceUniqueId is too big: uid={0} total_nb_face={1}",
647 face.uniqueId(),total_nb_face);
648 }
649}
650
651/*---------------------------------------------------------------------------*/
652/*---------------------------------------------------------------------------*/
653
654void CartesianMeshTesterModule::
655_testXmlInfos()
656{
657 info() << "PRINT Xml infos for <cartesian> mesh generator";
658 ICaseDocument* cd = subDomain()->caseDocument();
659 XmlNodeList mesh_elements = cd->meshElements();
660 if (mesh_elements.size()==0)
661 return;
662 XmlNode mesh_generator_element = mesh_elements[0].child("meshgenerator");
663 // Si nul, cela signifie qu'on n'utilise pas le 'meshgenerator'.
664 if (mesh_generator_element.null()){
665 info() << "No element <meshgenerator> found";
666 return;
667 }
668 XmlNode cartesian_node = mesh_generator_element.child("cartesian");
669 if (cartesian_node.null()){
670 info() << "No element <cartesian> found";
671 return;
672 }
673 XmlNode origine_node = cartesian_node.child("origine");
674 XmlNode nsd_node = cartesian_node.child("nsd");
675
676 // Récupère et affiche les infos pour <lx>.
677 XmlNodeList lx_node_list = cartesian_node.children("lx");
678 info() << "NB_X=" << lx_node_list.size();
679 for( XmlNode lx_node : lx_node_list ){
680 Real lx_value = lx_node.valueAsReal(true);
681 Integer nx_value = lx_node.attr("nx",true).valueAsInteger(true);
682 Real px_value = lx_node.attr("prx").valueAsReal(true);
683 info() << "V=" << lx_value << " nx=" << nx_value << " px=" << px_value;
684 }
685}
686
687/*---------------------------------------------------------------------------*/
688/*---------------------------------------------------------------------------*/
689
692{
693 if (!options()->unstructuredMeshFile.isPresent())
694 return;
695 // NOTE: On utilise explicitement le namespace Arcane
696 // pour que la documentation générée par doxygen génère les
697 // liens correctement.
698
700 // file_name est le nom du fichier de maillage non structuré
701
702 Arcane::String file_name = options()->unstructuredMeshFile();
703 info() << "UnstructuredMeshFileName=" << file_name;
704
705 Arcane::ISubDomain* sd = subDomain();
706 Arcane::ICartesianMesh* cartesian_mesh = m_cartesian_mesh;
707 Arcane::IMesh* current_mesh = cartesian_mesh->mesh();
708 Arcane::IParallelMng* pm = current_mesh->parallelMng();
709
710 Arcane::MeshReaderMng reader_mng(sd);
711 Arcane::IMesh* new_mesh = reader_mng.readMesh("UnstructuredMesh2",file_name,pm);
712 info() << "MESH=" << new_mesh;
713
714 // Création du service de partitionnement
716 auto partitioner_ref = sbuilder.createReference("SimpleGridMeshPartitioner",new_mesh);
717 Arcane::IGridMeshPartitioner* partitioner = partitioner_ref.get();
718
719 // Positionne les coordonnées de notre sous-domaine dans la grille
720 Int32 sd_x = cartesian_mesh->cellDirection(MD_DirX).subDomainOffset();
721 Int32 sd_y = cartesian_mesh->cellDirection(MD_DirY).subDomainOffset();
722 Int32 sd_z = cartesian_mesh->cellDirection(MD_DirZ).subDomainOffset();
723 partitioner->setPartIndex(sd_x,sd_y,sd_z);
724
725 // Positionne la bounding box de notre sous-domaine.
726 // Pour cela, parcours uniquement nos noeuds et prend les coordonnées min et max
727 Real max_value = FloatInfo<Real>::maxValue();
728 Real min_value = -max_value;
729 Arcane::Real3 min_box(max_value,max_value,max_value);
730 Arcane::Real3 max_box(min_value,min_value,min_value);
731 VariableNodeReal3& nodes_coord = current_mesh->nodesCoordinates();
732 ENUMERATE_(Cell,icell,current_mesh->ownCells()){
733 Cell cell{*icell};
734 for( Node node : cell.nodes() ){
735 Real3 coord = nodes_coord[node];
736 min_box = math::min(min_box,coord);
737 max_box = math::max(max_box,coord);
738 }
739 }
740 partitioner->setBoundingBox(min_box,max_box);
741
742 // Applique le partitionnement
743 partitioner->applyMeshPartitioning(new_mesh);
745
746 // Maintenant, écrit le fichier du maillage non structuré et de notre partie
747 // cartésienne.
748 const bool is_debug = false;
749 if (is_debug){
750 ServiceBuilder<IMeshWriter> sbuilder2(sd);
751 auto mesh_writer = sbuilder2.createReference("VtkLegacyMeshWriter",SB_Collective);
752 {
753 StringBuilder fname = "cut_mesh_";
754 fname += pm->commRank();
755 fname += ".vtk";
756 mesh_writer->writeMeshToFile(new_mesh,fname);
757 }
758 {
759 StringBuilder fname = "my_mesh_";
760 fname += pm->commRank();
761 fname += ".vtk";
762 mesh_writer->writeMeshToFile(current_mesh,fname);
763 }
764 }
765}
766
767/*---------------------------------------------------------------------------*/
768/*---------------------------------------------------------------------------*/
769
770void CartesianMeshTesterModule::
771_checkNearlyEqual(Real3 a,Real3 b,const String& message)
772{
773 info() << "A=" << a;
774 info() << "B=" << b;
775 if (!math::isNearlyEqual(a.x,b.x))
776 ARCANE_FATAL("Bad value X expected={0} value={1} message={2}",a.x,b.x,message);
777 if (!math::isNearlyEqual(a.y,b.y))
778 ARCANE_FATAL("Bad value Y expected={0} value={1} message={2}",a.y,b.y,message);
779 if (!math::isNearlyEqual(a.z,b.z))
780 ARCANE_FATAL("Bad value Z expected={0} value={1} message={2}",a.z,b.z,message);
781}
782
783/*---------------------------------------------------------------------------*/
784/*---------------------------------------------------------------------------*/
785
786void CartesianMeshTesterModule::
787_printCartesianMeshInfos()
788{
789 auto* cartesian_info = ICartesianMeshGenerationInfo::getReference(defaultMesh(),false);
790 if (!cartesian_info)
791 ARCANE_FATAL("No cartesian info");
792
793 info() << "Test: _printCartesianMeshInfos()";
794 info() << " Origin=" << cartesian_info->globalOrigin();
795 info() << " Length=" << cartesian_info->globalLength();
796
797 if (options()->expectedMeshOrigin.isPresent())
798 _checkNearlyEqual(cartesian_info->globalOrigin(),options()->expectedMeshOrigin(),"Origin");
799 if (options()->expectedMeshLength.isPresent())
800 _checkNearlyEqual(cartesian_info->globalLength(),options()->expectedMeshLength(),"Length");
801}
802
803/*---------------------------------------------------------------------------*/
804/*---------------------------------------------------------------------------*/
805
806void CartesianMeshTesterModule::
807_checkSpecificApplyOperator()
808{
810 CellGroup all_cells = allCells();
811 Int32 nb_item = all_cells.size();
812 Int32 dim = mesh()->dimension();
813 all_cells.applyOperation(&op);
814 eMeshStructure mk = mesh()->meshKind().meshStructure();
815 info() << "MeshStructure=" << mk;
816 if (mk != eMeshStructure::Cartesian)
817 ARCANE_FATAL("Invalid mesh structure v={0} (expected 'Cartesian')", mk);
818 if (dim == 3) {
819 if (nb_item != op.m_nb_hexa8)
820 ARCANE_FATAL("Bad number of Hexa8 n={0} expected={1}", op.m_nb_hexa8, nb_item);
821 }
822 else if (dim == 2) {
823 if (nb_item != op.m_nb_quad4)
824 ARCANE_FATAL("Bad number of Quad8 n={0} expected={1}", op.m_nb_quad4, nb_item);
825 }
826}
827
828/*---------------------------------------------------------------------------*/
829/*---------------------------------------------------------------------------*/
830
831ARCANE_REGISTER_MODULE_CARTESIANMESHTESTER(CartesianMeshTesterModule);
832
833/*---------------------------------------------------------------------------*/
834/*---------------------------------------------------------------------------*/
835
836} // End namespace ArcaneTest
837
838/*---------------------------------------------------------------------------*/
839/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_FACE(name, group)
Enumérateur générique d'un groupe de faces.
#define ENUMERATE_(type, name, group)
Enumérateur générique d'un groupe d'entité
#define ENUMERATE_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
#define ENUMERATE_NODE(name, group)
Enumérateur générique d'un groupe de noeuds.
Fonctions mathématiques diverses.
Fonctions utilitaires sur le maillage.
Ce fichier contient les différentes fabriques de services et macro pour enregistrer les services.
#define ARCANE_SERVICE_INTERFACE(ainterface)
Macro pour déclarer une interface lors de l'enregistrement d'un service.
void partitionAndDistributeMeshes(ConstArrayView< IMesh * > meshes) override
Partitionne les maillages.
void notifyEndPartition() override
Notification lors de la fin d'un repartionnement (après échange des entités)
void build() override
Construction de niveau build du service.
void partitionMesh(bool initial_partition) override
IPrimaryMesh * primaryMesh() override
Maillage associé
Module de test pour les infos sur les maillages cartésiens.
void _sample(ICartesianMesh *cartesian_mesh)
Opérateur abstrait sur des entités rangées par type.
Informations de connectivité d'un maillage cartésien.
Cell lowerRight(Node n) const
Maille en bas à droite du noeud n.
Cell upperLeft(Node n) const
Maille en haut à gauche du noeud n.
Cell lowerLeft(Node n) const
Maille en bas à gauche du noeud n.
Cell upperRight(Node n) const
Maille en haut à droite du noeud n.
Int32 subDomainOffset() const
Offset dans cette direction du sous-domaine.
Maille d'un maillage.
Definition Item.h:1191
Int32 nbHChildren() const
Nombre d'enfants pour l'AMR.
Definition Item.h:1307
Cell hChild(Int32 i) const
i-ème enfant AMR
Definition Item.h:1310
Int32 level() const
Definition Item.h:1342
void clear()
Supprime tous les éléments de la collection.
Definition Collection.h:68
Vue constante d'un tableau de type T.
Face d'une maille.
Definition Item.h:944
Informations sur le type flottant.
Definition Limits.h:48
virtual ITraceMng * traceMng() const =0
Gestionnaire de traces.
virtual CellGroup cells()=0
Groupe de mailles du patch.
Interface d'un maillage cartésien.
static ICartesianMesh * getReference(const MeshHandleOrMesh &mesh, bool create=true)
Récupère ou créé la référence associée à mesh.
virtual CellDirectionMng cellDirection(eMeshDirection dir)=0
Liste des mailles dans la direction dir.
virtual CartesianConnectivity connectivity()=0
Informations sur la connectivité
virtual IMesh * mesh() const =0
Maillage associé à ce maillage cartésien.
virtual const XmlNodeList & meshElements()=0
Retourne l'élément racine des informations de maillage.
Interface d'un partitionneur de maillage sur une grille.
virtual void setBoundingBox(Real3 min_val, Real3 max_val)=0
Positionne la bounding box de notre sous-domaine.
virtual void applyMeshPartitioning(IMesh *mesh)=0
Applique le repartitionnement sur le maillage mesh.
virtual void setPartIndex(Int32 i, Int32 j, Int32 k)=0
Indice (i,j,k) de la partie.
Interface d'un partitionneur initial.
Interface d'une famille d'entités.
Definition IItemFamily.h:84
virtual ItemGroup allItems() const =0
Groupe de toutes les entités.
virtual ItemGroup createGroup(const String &name, Int32ConstArrayView local_ids, bool do_override=false)=0
Créé un groupe d'entités de nom name contenant les entités local_ids.
virtual VariableItemInt32 & itemsNewOwner()=0
Variable contenant le numéro du nouveau sous-domaine propriétaire de l'entité.
virtual CellGroup ownCells()=0
Groupe de toutes les mailles propres au domaine.
virtual Integer dimension()=0
Dimension du maillage (1D, 2D ou 3D).
virtual IItemFamily * cellFamily()=0
Retourne la famille des mailles.
Interface d'un partitionneur de maillage.
virtual VariableNodeReal3 & nodesCoordinates()=0
Coordonnées des noeuds.
virtual IParallelMng * parallelMng()=0
Gestionnaire de parallèlisme.
virtual const MeshKind meshKind() const =0
Caractéristiques du maillage.
Interface du gestionnaire de parallélisme pour un sous-domaine.
virtual Int32 commRank() const =0
Rang de cette instance dans le communicateur.
virtual Int32 commSize() const =0
Nombre d'instance dans le communicateur.
Interface du gestionnaire d'un sous-domaine.
Definition ISubDomain.h:74
virtual ITimeLoopMng * timeLoopMng()=0
Retourne le gestionnaire de la boucle en temps.
virtual void setInitialPartitioner(IInitialPartitioner *partitioner)=0
Positionne le partitionneur initial.
virtual ITimeLoop * createTimeLoop(const String &name)=0
Crée une boucle en temps de nom name.
virtual void registerTimeLoop(ITimeLoop *time_loop)=0
Enregistrement et choix de la boucle en temps.
virtual void setRequiredModulesName(const StringCollection &)=0
Positionne la liste des des modules obligatoires.
virtual void setOptionalModulesName(const StringCollection &)=0
Positionne la liste des des modules facultatifs.
static const char * WBuild
appelé lors de la lecture du jeu de données
Definition ITimeLoop.h:50
static const char * WComputeLoop
appelé pendant la boucle de calcul
Definition ITimeLoop.h:48
virtual void setEntryPoints(const String &where, const TimeLoopEntryPointInfoCollection &)=0
Positionne la liste des noms des points d'entrée pour le point d'appel where.
static const char * WInit
appelé pendant l'initialisation, l'initialisation d'une reprise ou d'un nouveau cas
Definition ITimeLoop.h:52
Groupe d'entités de maillage.
Definition ItemGroup.h:49
Integer size() const
Nombre d'éléments du groupe.
Definition ItemGroup.h:88
void applyOperation(IItemOperationByBasicType *operation) const
Applique l'opération operation sur les entités du groupe.
Definition ItemGroup.cc:530
ItemGroup own() const
Groupe équivalent à celui-ci mais contenant uniquement les éléments propres au sous-domaine.
Definition ItemGroup.cc:189
Classe utilitaire pour imprimer les infos sur une entité.
Definition ItemPrinter.h:35
Vue sur un vecteur d'entités.
Int32 size() const
Nombre d'éléments du vecteur.
NodeConnectedListViewType nodes() const
Liste des noeuds de l'entité
Definition Item.h:782
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:776
NodeLocalIdView nodeIds() const
Liste des noeuds de l'entité
Definition Item.h:785
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:225
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:216
Gestionnaire de lecteurs de maillage.
IMesh * readMesh(const String &mesh_name, const String &file_name)
Lit le maillage dont le nom de fichier est file_name.
Informations pour construire un module.
ISubDomain * subDomain() const
Accès au sous-domaine associé
Noeud d'un maillage.
Definition Item.h:573
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Référence à une instance.
Structure contenant les informations pour créer un service.
Classe utilitaire pour instantier un service d'une interface donnée.
Ref< InterfaceType > createReference(const String &name, eServiceBuilderProperties properties=SB_None)
Créé une instance implémentant l'interface InterfaceType.
Propriétés de création d'un service.
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
TraceAccessor(ITraceMng *m)
Construit un accesseur via le gestionnaire de trace m.
TraceMessage info() const
Flot pour un message d'information.
Paramètres nécessaires à la construction d'une variable.
XmlNode child(const String &name) const
Noeud fils de celui-ci de nom name.
Definition XmlNode.cc:64
XmlNodeList children(const String &name) const
Ensemble des noeuds fils de ce noeud ayant pour nom name.
Definition XmlNode.cc:93
bool null() const
Vrai si le noeud est nul.
Definition XmlNode.h:294
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
MeshVariableScalarRefT< Cell, Real > VariableCellReal
Grandeur au centre des mailles de type réel.
MeshVariableScalarRefT< Node, Real > VariableNodeReal
Grandeur au noeud de type réel.
MeshVariableScalarRefT< Cell, Real3 > VariableCellReal3
Grandeur au centre des mailles de type coordonnées.
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
ItemVariableScalarRefT< Int32 > VariableItemInt32
Grandeur de type entier 32 bits.
MeshVariableScalarRefT< Face, Real3 > VariableFaceReal3
Grandeur aux faces de type coordonnées.
MeshVariableScalarRefT< Face, Int64 > VariableFaceInt64
Grandeur aux faces de type entier 64 bits.
ARCANE_CARTESIANMESH_EXPORT Ref< CartesianMeshCoarsening2 > createCartesianMeshCoarsening2(ICartesianMesh *cm)
Créé une instance pour gérer le déraffinement du maillage (V2).
Int32 toInt32(Int64 v)
Converti un Int64 en un Int32.
@ ReduceSum
Somme des valeurs.
constexpr __host__ __device__ bool isNearlyEqual(const _Type &a, const _Type &b)
Teste si deux valeurs sont à un peu près égales. Pour les types entiers, cette fonction est équivalen...
Definition Numeric.h:212
ARCCORE_BASE_EXPORT String getEnvironmentVariable(const String &name)
Variable d'environnement du nom name.
@ SB_Collective
Indique que tous les processus font la même opération.
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
eMeshStructure
Structure du maillage.
Definition MeshKind.h:29
@ ST_SubDomain
Le service s'utilise au niveau du sous-domaine.
@ MD_DirZ
Direction Z.
@ MD_DirY
Direction Y.
@ MD_DirX
Direction X.
UniqueArray< Int32 > Int32UniqueArray
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:428
List< String > StringList
Tableau de chaînes de caractères unicode.
Definition UtilsTypes.h:596
double Real
Type représentant un réel.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.
std::int32_t Int32
Type entier signé sur 32 bits.
Real y
deuxième composante du triplet
Definition Real3.h:36
Real z
troisième composante du triplet
Definition Real3.h:37
Real x
première composante du triplet
Definition Real3.h:35