Arcane  v3.14.10.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/*---------------------------------------------------------------------------*/
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
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();
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
141: public BasicService
143{
144 public:
146 : BasicService(sbi){}
147 public:
148 void build() override {}
149 void notifyEndPartition() override {}
150 IPrimaryMesh* primaryMesh() override { return mesh()->toPrimaryMesh(); }
152 {
154 return;
155 IMesh* mesh = this->mesh();
156 IParallelMng* pm = mesh->parallelMng();
157 Int32 nb_rank = pm->commSize();
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;
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;
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
188: public TraceAccessor
189, public IInitialPartitioner
190{
191 public:
192
194 : TraceAccessor(sd->traceMng()), m_sub_domain(sd)
195 {
196 }
197 void build() override {}
198 void partitionAndDistributeMeshes(ConstArrayView<IMesh*> meshes) 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 {
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 {
271 clist.add(TimeLoopEntryPointInfo("CartesianMeshTester.buildInit"));
272 time_loop->setEntryPoints(ITimeLoop::WBuild,clist);
273 }
274
275 {
277 clist.add(TimeLoopEntryPointInfo("CartesianMeshTester.init"));
278 time_loop->setEntryPoints(ITimeLoop::WInit,clist);
279 }
280
281 {
283 clist.add(TimeLoopEntryPointInfo("CartesianMeshTester.compute"));
284 time_loop->setEntryPoints(ITimeLoop::WComputeLoop,clist);
285 }
286
287 {
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
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 {
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 {
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));
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()){
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";
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();
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;
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()){
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()){
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
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();
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;
708 Arcane::IParallelMng* pm = current_mesh->parallelMng();
709
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);
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];
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){
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{
809 CountByBasicType op;
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 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.
Classe de base de service lié à un sous-domaine.
Informations de connectivité d'un maillage cartésien.
Infos sur les mailles d'une direction spécifique X,Y ou Z d'un maillage structuré.
Vue sur les informations des mailles.
Maille d'un maillage.
Definition Item.h:1178
Int32 nbHChildren() const
Nombre d'enfants pour l'AMR.
Definition Item.h:1293
Cell hChild(Int32 i) const
i-ème enfant AMR
Definition Item.h:1296
Int32 level() const
Definition Item.h:1328
Maille avant et après une maille suivant une direction.
Face d'une maille.
Definition Item.h:932
Informations sur le type flottant.
Definition Limits.h:48
Interface d'un patch AMR d'un maillage cartésien.
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 IMesh * mesh() const =0
Maillage associé à ce maillage cartésien.
virtual ICartesianMeshPatch * patch(Int32 index) const =0
Retourne le index-ième patch du maillage.
virtual Ref< CartesianMeshCoarsening > createCartesianMeshCoarsening()=0
Créé une instance pour gérer le déraffinement du maillage.
virtual void computeDirections()=0
Calcule les infos pour les accès par direction.
virtual Int32 nbPatch() const =0
Nombre de patchs du maillage.
Interface d'une classe gérant un document XML du jeu de données.
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.
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 IMeshModifier * modifier()=0
Interface de modification associée.
virtual IMeshUtilities * utilities()=0
Interface des fonctions utilitaires associée.
virtual const MeshKind meshKind() const =0
Caractéristiques du maillage.
virtual IPrimaryMesh * toPrimaryMesh()=0
Retourne l'instance sous la forme d'un IPrimaryMesh.
virtual bool isDynamic() const =0
Indique si le maillage est dynamique (peut évoluer)
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
Interface du gestionnaire de la boucle en temps.
Interface d'une boucle en temps.
Definition ITimeLoop.h:41
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
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
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:771
Int32 nbNode() const
Nombre de noeuds de l'entité
Definition Item.h:765
ItemUniqueId uniqueId() const
Identifiant unique sur tous les domaines.
Definition Item.h:216
constexpr bool null() const
true si l'entité est nul (i.e. non connecté au maillage)
Definition Item.h:207
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
Gestionnaire de lecteurs de maillage.
Informations pour construire un module.
Noeud d'un maillage.
Definition Dom.h:204
Classe gérant un vecteur de réel de dimension 3.
Definition Real3.h:132
Structure contenant les informations pour créer un service.
Propriétés de création d'un service.
Infos d'un point d'entrée d'une boucle en temps.
Paramètres nécessaires à la construction d'une variable.
Liste de noeuds d'un arbre DOM.
Definition XmlNodeList.h:33
Noeud d'un arbre DOM.
Definition XmlNode.h:51
Constructeur de chaîne de caractère unicode.
Chaîne de caractères unicode.
ITraceMng * traceMng() const
Gestionnaire de trace.
TraceMessage info() const
Flot pour un message d'information.
Vecteur 1D de données avec sémantique par valeur (style STL).
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ARCCORE_HOST_DEVICE Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
#define ARCANE_REGISTER_SERVICE(aclass, a_service_property,...)
Macro pour enregistrer un service.
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.
constexpr ARCCORE_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
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
@ SB_Collective
Indique que tous les processus font la même opération.
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.
Int32 Integer
Type représentant un entier.
auto makeRef(InstanceType *t) -> Ref< InstanceType >
Créé une référence sur un pointeur.