Arcane  v3.15.0.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
IncrementalComponentModifier.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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/* IncrementalComponentModifier.cc (C) 2000-2025 */
9/* */
10/* Modification incrémentale des constituants. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/materials/internal/IncrementalComponentModifier.h"
15
16#include "arcane/utils/ITraceMng.h"
17#include "arcane/utils/FunctorUtils.h"
18#include "arcane/utils/ValueConvert.h"
19
20#include "arcane/core/IItemFamily.h"
21#include "arcane/core/materials/IMeshMaterialVariable.h"
22
23#include "arcane/materials/internal/MeshMaterialMng.h"
24#include "arcane/materials/internal/ConstituentConnectivityList.h"
25#include "arcane/materials/internal/AllEnvData.h"
26
27#include "arcane/accelerator/core/ProfileRegion.h"
28
29/*---------------------------------------------------------------------------*/
30/*---------------------------------------------------------------------------*/
31
32namespace Arcane::Materials
33{
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
38IncrementalComponentModifier::
39IncrementalComponentModifier(AllEnvData* all_env_data, const RunQueue& queue)
40: TraceAccessor(all_env_data->traceMng())
41, m_all_env_data(all_env_data)
42, m_material_mng(all_env_data->m_material_mng)
43, m_work_info(queue.allocationOptions(), queue.memoryRessource())
44, m_queue(queue)
45{
46 // 0 si on utilise la copie typée (mode historique) et une commande par variable
47 // 1 si on utilise la copie générique et une commande par variable
48 // 2 si on utilise la copie générique et une commande pour toutes les variables
49 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_GENERIC_COPY_BETWEEN_PURE_AND_PARTIAL", true)) {
50 m_use_generic_copy_between_pure_and_partial = v.value();
51 }
52 else {
53 // Par défaut sur un accélérateur et en multi-threading, on utilise la copie
54 // avec une seule file, car c'est le mécanisme le plus performant.
55 if (queue.executionPolicy() != Accelerator::eExecutionPolicy::Sequential)
56 m_use_generic_copy_between_pure_and_partial = 2;
57 }
58 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_FORCE_MULTIPLE_COMMAND_FOR_MATERIAL_RESIZE", true)) {
59 m_force_multiple_command_for_resize = (v.value());
60 info() << "Force using multiple command for resize = " << m_force_multiple_command_for_resize;
61 }
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67void IncrementalComponentModifier::
68initialize(bool is_debug)
69{
70 m_is_debug = is_debug;
71 Int32 max_local_id = m_material_mng->mesh()->cellFamily()->maxLocalId();
72 Int32 nb_mat = m_material_mng->materials().size();
73 Int32 nb_env = m_material_mng->environments().size();
74 m_work_info.initialize(max_local_id, nb_mat, nb_env, m_queue);
75 m_work_info.is_verbose = is_debug || (traceMng()->verbosityLevel() >= 5);
76}
77
78/*---------------------------------------------------------------------------*/
79/*---------------------------------------------------------------------------*/
80
81void IncrementalComponentModifier::
82finalize()
83{
84}
85
86/*---------------------------------------------------------------------------*/
87/*---------------------------------------------------------------------------*/
100void IncrementalComponentModifier::
101_switchCellsForMaterials(const MeshMaterial* modified_mat,
103{
104 const bool is_add = m_work_info.isAdd();
105 const bool is_device = m_queue.isAcceleratorPolicy();
106 SmallSpan<const bool> is_materials_modified = m_work_info.m_is_materials_modified.view(false);
107
108 for (MeshEnvironment* true_env : m_material_mng->trueEnvironments()) {
109 for (MeshMaterial* mat : true_env->trueMaterials()) {
110 // Ne traite pas le matériau en cours de modification.
111 if (mat == modified_mat)
112 continue;
113
114 if (!is_materials_modified[mat->id()])
115 continue;
116
117 if (!is_device) {
118 m_work_info.pure_local_ids.clearHost();
119 m_work_info.partial_indexes.clearHost();
120 }
121
122 MeshMaterialVariableIndexer* indexer = mat->variableIndexer();
123
124 info(4) << "MatTransformCells is_add?=" << is_add << " indexer=" << indexer->name()
125 << " mat_id=" << mat->id();
126
127 Int32 nb_transformed = _computeCellsToTransformForMaterial(mat, ids);
128 info(4) << "nb_transformed=" << nb_transformed;
129 if (nb_transformed == 0)
130 continue;
131 indexer->transformCells(m_work_info, m_queue, false);
132 _resetTransformedCells(ids);
133
134 auto pure_local_ids = m_work_info.pure_local_ids.view(is_device);
135 auto partial_indexes = m_work_info.partial_indexes.view(is_device);
136
137 Int32 nb_pure = pure_local_ids.size();
138 Int32 nb_partial = partial_indexes.size();
139 info(4) << "NB_MAT_TRANSFORM pure=" << nb_pure
140 << " partial=" << nb_partial << " name=" << mat->name()
141 << " is_device?=" << is_device
142 << " is_modified?=" << is_materials_modified[mat->id()];
143
144 CopyBetweenPartialAndGlobalArgs args(indexer->index(), pure_local_ids,
145 partial_indexes,
146 m_do_copy_between_partial_and_pure,
147 is_add,
148 m_queue);
149 _copyBetweenPartialsAndGlobals(args);
150 }
151 }
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
168void IncrementalComponentModifier::
169_switchCellsForEnvironments(const IMeshEnvironment* modified_env,
171{
172 const bool is_add = m_work_info.isAdd();
173 const bool is_device = m_queue.isAcceleratorPolicy();
174 SmallSpan<const bool> is_environments_modified = m_work_info.m_is_environments_modified.view(false);
175
176 // Ne copie pas les valeurs partielles des milieux vers les valeurs globales
177 // en cas de suppression de mailles, car cela sera fait avec la valeur matériau
178 // correspondante. Cela permet d'avoir le même comportement que sans
179 // optimisation. Ce n'est pas actif par défaut pour compatibilité avec l'existant.
180 const bool is_copy = is_add || !(m_material_mng->isUseMaterialValueWhenRemovingPartialValue());
181
182 Int32 nb_transformed = _computeCellsToTransformForEnvironments(ids);
183 info(4) << "Compute Cells for environments nb_transformed=" << nb_transformed;
184 if (nb_transformed == 0)
185 return;
186
187 for (const MeshEnvironment* env : m_material_mng->trueEnvironments()) {
188 // Ne traite pas le milieu en cours de modification.
189 if (env == modified_env)
190 continue;
191 // Si je suis mono matériau, la mise à jour de l'indexeur a été faite par le matériau
192 if (env->isMonoMaterial())
193 continue;
194
195 const Int32 env_id = env->id();
196
198 continue;
199
200 if (!is_device) {
201 m_work_info.pure_local_ids.clearHost();
202 m_work_info.partial_indexes.clearHost();
203 }
204
205 MeshMaterialVariableIndexer* indexer = env->variableIndexer();
206
207 info(4) << "EnvTransformCells is_add?=" << is_add
208 << " env_id=" << env_id
209 << " indexer=" << indexer->name() << " nb_item=" << ids.size();
210
211 indexer->transformCells(m_work_info, m_queue, true);
212
213 SmallSpan<const Int32> pure_local_ids = m_work_info.pure_local_ids.view(is_device);
214 SmallSpan<const Int32> partial_indexes = m_work_info.partial_indexes.view(is_device);
215 const Int32 nb_pure = pure_local_ids.size();
216
217 info(4) << "NB_ENV_TRANSFORM nb_pure=" << nb_pure << " name=" << env->name()
218 << " is_modified=" << is_environments_modified[env_id];
219
220 if (is_copy) {
221 CopyBetweenPartialAndGlobalArgs copy_args(indexer->index(), pure_local_ids,
222 partial_indexes,
223 m_do_copy_between_partial_and_pure, is_add,
224 m_queue);
225 _copyBetweenPartialsAndGlobals(copy_args);
226 }
227 }
228
229 _resetTransformedCells(ids);
230}
231
232/*---------------------------------------------------------------------------*/
233/*---------------------------------------------------------------------------*/
237Int32 IncrementalComponentModifier::
238_computeCellsToTransformForMaterial(const MeshMaterial* mat, SmallSpan<const Int32> ids)
239{
240 const MeshEnvironment* env = mat->trueEnvironment();
241 const Int16 env_id = env->componentId();
242 bool is_add = m_work_info.isAdd();
243
244 ConstituentConnectivityList* connectivity = m_all_env_data->componentConnectivityList();
245 SmallSpan<bool> transformed_cells = m_work_info.transformedCells();
246 return connectivity->fillCellsToTransform(ids, env_id, transformed_cells, is_add, m_queue);
247}
248
249/*---------------------------------------------------------------------------*/
250/*---------------------------------------------------------------------------*/
264void IncrementalComponentModifier::
265_removeItemsFromEnvironment(MeshEnvironment* env, MeshMaterial* mat,
267{
268 info(4) << "MeshEnvironment::removeItemsDirect mat=" << mat->name();
269
270 Int32 nb_to_remove = local_ids.size();
271
272 // TODO: à faire dans finalize()
273 env->addToTotalNbCellMat(-nb_to_remove);
274
275 mat->variableIndexer()->endUpdateRemove(m_work_info, nb_to_remove, m_queue);
276
277 if (update_env_indexer) {
278 // Met aussi à jour les entités \a local_ids à l'indexeur du milieu.
279 // Cela n'est possible que si le nombre de matériaux du milieu
280 // est supérieur ou égal à 2 (car sinon le matériau et le milieu
281 // ont le même indexeur)
282 env->variableIndexer()->endUpdateRemove(m_work_info, nb_to_remove, m_queue);
283 }
284}
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
296void IncrementalComponentModifier::
297_addItemsToEnvironment(MeshEnvironment* env, MeshMaterial* mat,
299{
300 info(4) << "MeshEnvironment::addItemsDirect"
301 << " mat=" << mat->name();
302
303 MeshMaterialVariableIndexer* var_indexer = mat->variableIndexer();
304 const Int32 nb_to_add = local_ids.size();
305
306 // Met à jour le nombre de matériaux par maille et le nombre total de mailles matériaux.
307 env->addToTotalNbCellMat(nb_to_add);
308
309 const Int16 env_id = env->componentId();
310 m_work_info.m_cells_is_partial.resize(nb_to_add);
311 ConstituentConnectivityList* connectivity = m_all_env_data->componentConnectivityList();
312 connectivity->fillCellsIsPartial(local_ids, env_id, m_work_info.m_cells_is_partial.to1DSmallSpan(), m_queue);
313
314 _addItemsToIndexer(var_indexer, local_ids);
315
316 if (update_env_indexer) {
317 // Met aussi à jour les entités \a local_ids à l'indexeur du milieu.
318 // Cela n'est possible que si le nombre de matériaux du milieu
319 // est supérieur ou égal à 2 (car sinon le matériau et le milieu
320 // ont le même indexeur)
321 _addItemsToIndexer(env->variableIndexer(), local_ids);
322 }
323}
324
325/*---------------------------------------------------------------------------*/
326/*---------------------------------------------------------------------------*/
327
328void IncrementalComponentModifier::
329_addItemsToIndexer(MeshMaterialVariableIndexer* var_indexer,
331{
332 // TODO Conserver l'instance au cours de toutes modifications
333 ComponentItemListBuilder& list_builder = m_work_info.list_builder;
334 list_builder.setIndexer(var_indexer);
335
336 const Int32 nb_id = local_ids.size();
337 list_builder.preAllocate(nb_id);
338
339 _computeItemsToAdd(list_builder, local_ids);
340
341 if (traceMng()->verbosityLevel() >= 5)
342 info() << "ADD_MATITEM_TO_INDEXER component=" << var_indexer->name()
343 << " nb_pure=" << list_builder.pureIndexes().size()
344 << " nb_partial=" << list_builder.partialIndexes().size()
345 << "\n pure=(" << list_builder.pureIndexes() << ")"
346 << "\n partial=(" << list_builder.partialIndexes() << ")";
347
348 // TODO: lors de cet appel, on connait le max de \a index_in_partial donc
349 // on peut éviter de faire une réduction pour le recalculer.
350
351 var_indexer->endUpdateAdd(list_builder, m_queue);
352
353 // Redimensionne les variables
354 _resizeVariablesIndexer(var_indexer->index());
355
356 // Maintenant que les nouveaux MatVar sont créés, il faut les
357 // initialiser avec les bonnes valeurs.
358 if (m_do_init_new_items) {
359 IMeshMaterialMng* mm = m_material_mng;
360 bool init_with_zero = mm->isDataInitialisationWithZero();
361
362 Accelerator::ProfileRegion ps(m_queue, "InitializeNewItems", 0xFFFF00);
363
364 SmallSpan<Int32> partial_indexes = list_builder.partialIndexes();
365 if (init_with_zero) {
366 RunQueue::ScopedAsync sc(&m_queue);
367 InitializeWithZeroArgs init_args(var_indexer->index(), partial_indexes, m_queue);
368
369 bool do_one_command = (m_use_generic_copy_between_pure_and_partial == 2);
370 UniqueArray<CopyBetweenDataInfo>& copy_data = m_work_info.m_host_variables_copy_data;
371 if (do_one_command) {
372 copy_data.clear();
373 copy_data.reserve(m_material_mng->nbVariable());
374 init_args.m_copy_data = &copy_data;
375 }
376
377 auto func_zero = [&](IMeshMaterialVariable* mv) {
378 mv->_internalApi()->initializeNewItemsWithZero(init_args);
379 };
380 functor::apply(mm, &IMeshMaterialMng::visitVariables, func_zero);
381
382 if (do_one_command){
383 MDSpan<CopyBetweenDataInfo, MDDim1> x(copy_data.data(), MDIndex<1>(copy_data.size()));
384 m_work_info.m_variables_copy_data.copy(x, &m_queue);
385 _applyInitializeWithZero(init_args);
386 }
387 m_queue.barrier();
388 }
389 else {
390 SmallSpan<Int32> partial_local_ids = list_builder.partialLocalIds();
391
392 CopyBetweenPartialAndGlobalArgs args(var_indexer->index(), partial_local_ids,
393 partial_indexes, true, true, m_queue);
394 _copyBetweenPartialsAndGlobals(args);
395 }
396 }
397}
398
399/*---------------------------------------------------------------------------*/
400/*---------------------------------------------------------------------------*/
404void IncrementalComponentModifier::
405_resizeVariablesIndexer(Int32 var_index)
406{
407 Accelerator::ProfileRegion ps(m_queue, "ResizeVariableIndexer", 0xFF00FF);
409 // Regarde si on n'utilise qu'une seule commande pour les copies des vues.
410 // Pour l'instant (novembre 2024) on ne l'utilise par défaut que si
411 // on est sur accélérateur.
412 bool do_one_command = (m_use_generic_copy_between_pure_and_partial == 2);
413
414 if (m_force_multiple_command_for_resize)
415 do_one_command = false;
416
417 UniqueArray<CopyBetweenDataInfo>& copy_data = m_work_info.m_host_variables_copy_data;
418 if (do_one_command) {
419 copy_data.clear();
420 copy_data.reserve(m_material_mng->nbVariable());
421 resize_args.m_copy_data = &copy_data;
422 }
423
424 if (m_force_multiple_command_for_resize) {
425 // Le mode de commandes multiples sert à identifier quelles variables
426 // sont encore sur CPU via le déclenchement de PageFault.
427 // C'est pour cela qu'on met le nom de la variable dans la région de profiling
428 // pour avoir les traces avec 'nsys' par exemple. Il faut aussi ajouter
429 // une barrière pour sérialiser les opérations.
430 auto func2 = [&](IMeshMaterialVariable* mv) {
431 Accelerator::ProfileRegion ps2(m_queue, String("Resize_") + mv->name());
432 auto* mvi = mv->_internalApi();
433 mvi->resizeForIndexer(resize_args);
434 m_queue.barrier();
435 };
436 functor::apply(m_material_mng, &MeshMaterialMng::visitVariables, func2);
437 }
438 else {
439 RunQueue::ScopedAsync sc(&m_queue);
440 auto func1 = [&](IMeshMaterialVariable* mv) {
441 auto* mvi = mv->_internalApi();
442 mvi->resizeForIndexer(resize_args);
443 };
444 functor::apply(m_material_mng, &MeshMaterialMng::visitVariables, func1);
445 }
446
447 if (do_one_command) {
448 // Copie 'copy_data' dans le tableau correspondant pour le device éventuel.
450 m_work_info.m_variables_copy_data.copy(x, &m_queue);
451 _applyCopyVariableViews(m_queue);
452 }
453
454 m_queue.barrier();
455}
456
457/*---------------------------------------------------------------------------*/
458/*---------------------------------------------------------------------------*/
466void IncrementalComponentModifier::
467_copyBetweenPartialsAndGlobals(const CopyBetweenPartialAndGlobalArgs& args)
468{
469 if (args.m_local_ids.empty())
470 return;
471 const bool do_copy = args.m_do_copy_between_partial_and_pure;
472 const bool is_add_operation = args.m_is_global_to_partial;
473 RunQueue queue(args.m_queue);
475 // Comme on a modifié des mailles, il faut mettre à jour les valeurs
476 // correspondantes pour chaque variable.
477 //info(4) << "NB_TRANSFORM=" << nb_transform << " name=" << e->name();
478 //Integer indexer_index = indexer->index();
479
480 Accelerator::RunQueuePool& queue_pool = m_material_mng->_internalApi()->asyncRunQueuePool();
481
482 // Redimensionne les variables si nécessaire
483 if (is_add_operation) {
484 _resizeVariablesIndexer(args.m_var_index);
485 }
486
487 if (do_copy) {
488 bool do_one_command = (m_use_generic_copy_between_pure_and_partial == 2);
489 UniqueArray<CopyBetweenDataInfo>& copy_data = m_work_info.m_host_variables_copy_data;
490 copy_data.clear();
491 copy_data.reserve(m_material_mng->nbVariable());
492
493 Int32 index = 0;
495 args2.m_use_generic_copy = (m_use_generic_copy_between_pure_and_partial >= 1);
496 if (do_one_command)
497 args2.m_copy_data = &copy_data;
498 auto func2 = [&](IMeshMaterialVariable* mv) {
499 auto* mvi = mv->_internalApi();
500 if (!do_one_command)
501 args2.m_queue = queue_pool[index];
502 mvi->copyBetweenPartialAndGlobal(args2);
503 ++index;
504 };
505 functor::apply(m_material_mng, &MeshMaterialMng::visitVariables, func2);
506 if (do_one_command) {
507 // Copie 'copy_data' dans le tableau correspondant pour le device éventuel.
509 m_work_info.m_variables_copy_data.copy(x, &queue);
510 _applyCopyBetweenPartialsAndGlobals(args2, queue);
511 }
512 else
513 queue_pool.barrier();
514 }
515}
516
517/*---------------------------------------------------------------------------*/
518/*---------------------------------------------------------------------------*/
519
520} // End namespace Arcane::Materials
521
522/*---------------------------------------------------------------------------*/
523/*---------------------------------------------------------------------------*/
Région pour le profiling.
Collection de RunQueue.
Permet de modifier l'asynchronisme de la file pendant la durée de vie de l'instance.
File d'exécution pour un accélérateur.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:149
Classe d'aide à la construction d'une liste de ComponentItem pour un MeshMaterialVariableIndexer.
Gestion des listes de connectivité des constituants.
Int32 fillCellsToTransform(SmallSpan< const Int32 > cells_local_id, Int16 env_id, SmallSpan< bool > cells_do_transform, bool is_add, RunQueue &queue)
Replit cells_do_transform en indiquant is la maille passe de pure à partielle.
void fillCellsIsPartial(SmallSpan< const Int32 > cells_local_id, Int16 env_id, SmallSpan< bool > cells_is_partial, RunQueue &queue)
Replit cells_is_partial en indiquant is la maille est partielle pour le milieu env_id.
Arguments des méthodes de copie entre valeurs partielles et globales.
Interface du gestionnaire des matériaux et des milieux d'un maillage.
Interface d'une variable matériau d'un maillage.
Arguments des méthodes de copie entre valeurs partielles et globales.
void transformCells(ConstituentModifierWorkInfo &args, RunQueue &queue, bool is_from_env)
Transforme des mailles entre pure et partielle.
const String & name() const
Nom de l'indexeur.
Matériau d'un maillage.
Arguments des méthodes de copie entre valeurs partielles et globales.
constexpr ARCCORE_HOST_DEVICE bool empty() const noexcept
Retourne true si le tableau est vide (dimension nulle)
Definition Span.h:372
constexpr ARCCORE_HOST_DEVICE SizeType size() const noexcept
Retourne la taille du tableau.
Definition Span.h:209
Chaîne de caractères unicode.
Active toujours les traces dans les parties Arcane concernant les matériaux.