Arcane  v3.14.10.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-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/* IncrementalComponentModifier.cc (C) 2000-2024 */
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 on utilise la copie avec une seule file
54 // car c'est la plus performante.
55 if (queue.isAcceleratorPolicy())
56 m_use_generic_copy_between_pure_and_partial = 2;
57 }
58}
59
60/*---------------------------------------------------------------------------*/
61/*---------------------------------------------------------------------------*/
62
63void IncrementalComponentModifier::
64initialize(bool is_debug)
65{
66 m_is_debug = is_debug;
67 Int32 max_local_id = m_material_mng->mesh()->cellFamily()->maxLocalId();
68 Int32 nb_mat = m_material_mng->materials().size();
69 Int32 nb_env = m_material_mng->environments().size();
70 m_work_info.initialize(max_local_id, nb_mat, nb_env, m_queue);
71 m_work_info.is_verbose = is_debug || (traceMng()->verbosityLevel() >= 5);
72}
73
74/*---------------------------------------------------------------------------*/
75/*---------------------------------------------------------------------------*/
76
77void IncrementalComponentModifier::
78finalize()
79{
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
96void IncrementalComponentModifier::
97_switchCellsForMaterials(const MeshMaterial* modified_mat,
99{
100 const bool is_add = m_work_info.isAdd();
101 const bool is_device = m_queue.isAcceleratorPolicy();
102 SmallSpan<const bool> is_materials_modified = m_work_info.m_is_materials_modified.view(false);
103
104 for (MeshEnvironment* true_env : m_material_mng->trueEnvironments()) {
105 for (MeshMaterial* mat : true_env->trueMaterials()) {
106 // Ne traite pas le matériau en cours de modification.
107 if (mat == modified_mat)
108 continue;
109
110 if (!is_materials_modified[mat->id()])
111 continue;
112
113 if (!is_device) {
114 m_work_info.pure_local_ids.clearHost();
115 m_work_info.partial_indexes.clearHost();
116 }
117
118 MeshMaterialVariableIndexer* indexer = mat->variableIndexer();
119
120 info(4) << "MatTransformCells is_add?=" << is_add << " indexer=" << indexer->name()
121 << " mat_id=" << mat->id();
122
123 Int32 nb_transformed = _computeCellsToTransformForMaterial(mat, ids);
124 info(4) << "nb_transformed=" << nb_transformed;
125 if (nb_transformed == 0)
126 continue;
127 indexer->transformCells(m_work_info, m_queue, false);
128 _resetTransformedCells(ids);
129
130 auto pure_local_ids = m_work_info.pure_local_ids.view(is_device);
131 auto partial_indexes = m_work_info.partial_indexes.view(is_device);
132
133 Int32 nb_pure = pure_local_ids.size();
134 Int32 nb_partial = partial_indexes.size();
135 info(4) << "NB_MAT_TRANSFORM pure=" << nb_pure
136 << " partial=" << nb_partial << " name=" << mat->name()
137 << " is_device?=" << is_device
138 << " is_modified?=" << is_materials_modified[mat->id()];
139
140 CopyBetweenPartialAndGlobalArgs args(indexer->index(), pure_local_ids,
141 partial_indexes,
142 m_do_copy_between_partial_and_pure,
143 is_add,
144 m_queue);
145 _copyBetweenPartialsAndGlobals(args);
146 }
147 }
148}
149
150/*---------------------------------------------------------------------------*/
151/*---------------------------------------------------------------------------*/
164void IncrementalComponentModifier::
165_switchCellsForEnvironments(const IMeshEnvironment* modified_env,
167{
168 const bool is_add = m_work_info.isAdd();
169 const bool is_device = m_queue.isAcceleratorPolicy();
170 SmallSpan<const bool> is_environments_modified = m_work_info.m_is_environments_modified.view(false);
171
172 // Ne copie pas les valeurs partielles des milieux vers les valeurs globales
173 // en cas de suppression de mailles, car cela sera fait avec la valeur matériau
174 // correspondante. Cela permet d'avoir le même comportement que sans
175 // optimisation. Ce n'est pas actif par défaut pour compatibilité avec l'existant.
176 const bool is_copy = is_add || !(m_material_mng->isUseMaterialValueWhenRemovingPartialValue());
177
178 Int32 nb_transformed = _computeCellsToTransformForEnvironments(ids);
179 info(4) << "Compute Cells for environments nb_transformed=" << nb_transformed;
180 if (nb_transformed == 0)
181 return;
182
183 for (const MeshEnvironment* env : m_material_mng->trueEnvironments()) {
184 // Ne traite pas le milieu en cours de modification.
185 if (env == modified_env)
186 continue;
187 // Si je suis mono matériau, la mise à jour de l'indexeur a été faite par le matériau
188 if (env->isMonoMaterial())
189 continue;
190
191 const Int32 env_id = env->id();
192
194 continue;
195
196 if (!is_device) {
197 m_work_info.pure_local_ids.clearHost();
198 m_work_info.partial_indexes.clearHost();
199 }
200
201 MeshMaterialVariableIndexer* indexer = env->variableIndexer();
202
203 info(4) << "EnvTransformCells is_add?=" << is_add
204 << " env_id=" << env_id
205 << " indexer=" << indexer->name() << " nb_item=" << ids.size();
206
207 indexer->transformCells(m_work_info, m_queue, true);
208
209 SmallSpan<const Int32> pure_local_ids = m_work_info.pure_local_ids.view(is_device);
210 SmallSpan<const Int32> partial_indexes = m_work_info.partial_indexes.view(is_device);
211 const Int32 nb_pure = pure_local_ids.size();
212
213 info(4) << "NB_ENV_TRANSFORM nb_pure=" << nb_pure << " name=" << env->name()
214 << " is_modified=" << is_environments_modified[env_id];
215
216 if (is_copy) {
217 CopyBetweenPartialAndGlobalArgs copy_args(indexer->index(), pure_local_ids,
218 partial_indexes,
219 m_do_copy_between_partial_and_pure, is_add,
220 m_queue);
221 _copyBetweenPartialsAndGlobals(copy_args);
222 }
223 }
224
225 _resetTransformedCells(ids);
226}
227
228/*---------------------------------------------------------------------------*/
229/*---------------------------------------------------------------------------*/
233Int32 IncrementalComponentModifier::
234_computeCellsToTransformForMaterial(const MeshMaterial* mat, SmallSpan<const Int32> ids)
235{
236 const MeshEnvironment* env = mat->trueEnvironment();
237 const Int16 env_id = env->componentId();
238 bool is_add = m_work_info.isAdd();
239
240 ConstituentConnectivityList* connectivity = m_all_env_data->componentConnectivityList();
241 SmallSpan<bool> transformed_cells = m_work_info.transformedCells();
242 return connectivity->fillCellsToTransform(ids, env_id, transformed_cells, is_add, m_queue);
243}
244
245/*---------------------------------------------------------------------------*/
246/*---------------------------------------------------------------------------*/
260void IncrementalComponentModifier::
261_removeItemsFromEnvironment(MeshEnvironment* env, MeshMaterial* mat,
263{
264 info(4) << "MeshEnvironment::removeItemsDirect mat=" << mat->name();
265
266 Int32 nb_to_remove = local_ids.size();
267
268 // TODO: à faire dans finalize()
269 env->addToTotalNbCellMat(-nb_to_remove);
270
271 mat->variableIndexer()->endUpdateRemove(m_work_info, nb_to_remove, m_queue);
272
273 if (update_env_indexer) {
274 // Met aussi à jour les entités \a local_ids à l'indexeur du milieu.
275 // Cela n'est possible que si le nombre de matériaux du milieu
276 // est supérieur ou égal à 2 (car sinon le matériau et le milieu
277 // ont le même indexeur)
278 env->variableIndexer()->endUpdateRemove(m_work_info, nb_to_remove, m_queue);
279 }
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
292void IncrementalComponentModifier::
293_addItemsToEnvironment(MeshEnvironment* env, MeshMaterial* mat,
295{
296 info(4) << "MeshEnvironment::addItemsDirect"
297 << " mat=" << mat->name();
298
299 MeshMaterialVariableIndexer* var_indexer = mat->variableIndexer();
300 const Int32 nb_to_add = local_ids.size();
301
302 // Met à jour le nombre de matériaux par maille et le nombre total de mailles matériaux.
303 env->addToTotalNbCellMat(nb_to_add);
304
305 const Int16 env_id = env->componentId();
306 m_work_info.m_cells_is_partial.resize(nb_to_add);
307 ConstituentConnectivityList* connectivity = m_all_env_data->componentConnectivityList();
308 connectivity->fillCellsIsPartial(local_ids, env_id, m_work_info.m_cells_is_partial.to1DSmallSpan(), m_queue);
309
310 _addItemsToIndexer(var_indexer, local_ids);
311
312 if (update_env_indexer) {
313 // Met aussi à jour les entités \a local_ids à l'indexeur du milieu.
314 // Cela n'est possible que si le nombre de matériaux du milieu
315 // est supérieur ou égal à 2 (car sinon le matériau et le milieu
316 // ont le même indexeur)
317 _addItemsToIndexer(env->variableIndexer(), local_ids);
318 }
319}
320
321/*---------------------------------------------------------------------------*/
322/*---------------------------------------------------------------------------*/
323
324void IncrementalComponentModifier::
325_addItemsToIndexer(MeshMaterialVariableIndexer* var_indexer,
327{
328 // TODO Conserver l'instance au cours de toutes modifications
329 ComponentItemListBuilder& list_builder = m_work_info.list_builder;
330 list_builder.setIndexer(var_indexer);
331
332 const Int32 nb_id = local_ids.size();
333 list_builder.preAllocate(nb_id);
334
335 _computeItemsToAdd(list_builder, local_ids);
336
337 if (traceMng()->verbosityLevel() >= 5)
338 info() << "ADD_MATITEM_TO_INDEXER component=" << var_indexer->name()
339 << " nb_pure=" << list_builder.pureIndexes().size()
340 << " nb_partial=" << list_builder.partialIndexes().size()
341 << "\n pure=(" << list_builder.pureIndexes() << ")"
342 << "\n partial=(" << list_builder.partialIndexes() << ")";
343
344 // TODO: lors de cet appel, on connait le max de \a index_in_partial donc
345 // on peut éviter de faire une réduction pour le recalculer.
346
347 var_indexer->endUpdateAdd(list_builder, m_queue);
348
349 // Redimensionne les variables
350 _resizeVariablesIndexer(var_indexer->index());
351
352 // Maintenant que les nouveaux MatVar sont créés, il faut les
353 // initialiser avec les bonnes valeurs.
354 if (m_do_init_new_items) {
355 IMeshMaterialMng* mm = m_material_mng;
356 bool init_with_zero = mm->isDataInitialisationWithZero();
357
358 Accelerator::ProfileRegion ps(m_queue, "InitializeNewItems", 0xFFFF00);
359
360 SmallSpan<Int32> partial_indexes = list_builder.partialIndexes();
361 if (init_with_zero) {
362 RunQueue::ScopedAsync sc(&m_queue);
363 InitializeWithZeroArgs init_args(var_indexer->index(), partial_indexes, m_queue);
364
365 bool do_one_command = (m_use_generic_copy_between_pure_and_partial == 2);
366 UniqueArray<CopyBetweenDataInfo>& copy_data = m_work_info.m_host_variables_copy_data;
367 if (do_one_command) {
368 copy_data.clear();
369 copy_data.reserve(m_material_mng->nbVariable());
370 init_args.m_copy_data = &copy_data;
371 }
372
373 auto func_zero = [&](IMeshMaterialVariable* mv) {
374 mv->_internalApi()->initializeNewItemsWithZero(init_args);
375 };
376 functor::apply(mm, &IMeshMaterialMng::visitVariables, func_zero);
377
378 if (do_one_command){
379 MDSpan<CopyBetweenDataInfo, MDDim1> x(copy_data.data(), MDIndex<1>(copy_data.size()));
380 m_work_info.m_variables_copy_data.copy(x, &m_queue);
381 _applyInitializeWithZero(init_args);
382 }
383 m_queue.barrier();
384 }
385 else {
386 SmallSpan<Int32> partial_local_ids = list_builder.partialLocalIds();
387
388 CopyBetweenPartialAndGlobalArgs args(var_indexer->index(), partial_local_ids,
389 partial_indexes, true, true, m_queue);
390 _copyBetweenPartialsAndGlobals(args);
391 }
392 }
393}
394
395/*---------------------------------------------------------------------------*/
396/*---------------------------------------------------------------------------*/
400void IncrementalComponentModifier::
401_resizeVariablesIndexer(Int32 var_index)
402{
403 RunQueue& queue = m_material_mng->_internalApi()->runQueue();
404 RunQueue::ScopedAsync sc(&m_queue);
405 Accelerator::ProfileRegion ps(queue, "ResizeVariableIndexer", 0xFF00FF);
407 // Regarde si on n'utilise qu'une seule commande pour les copies des vues.
408 // Pour l'instant (novembre 2024) on ne l'utilise par défaut que si
409 // on est sur accélérateur.
410 bool do_one_command = (m_use_generic_copy_between_pure_and_partial == 2);
411 UniqueArray<CopyBetweenDataInfo>& copy_data = m_work_info.m_host_variables_copy_data;
412 if (do_one_command) {
413 copy_data.clear();
414 copy_data.reserve(m_material_mng->nbVariable());
415 resize_args.m_copy_data = &copy_data;
416 }
417
418 auto func1 = [&](IMeshMaterialVariable* mv) {
419 auto* mvi = mv->_internalApi();
420 mvi->resizeForIndexer(resize_args);
421 };
422 functor::apply(m_material_mng, &MeshMaterialMng::visitVariables, func1);
423
424 if (do_one_command) {
425 // Copie 'copy_data' dans le tableau correspondant pour le device éventuel.
427 m_work_info.m_variables_copy_data.copy(x, &queue);
428 _applyCopyVariableViews(queue);
429 }
430
431 queue.barrier();
432}
433
434/*---------------------------------------------------------------------------*/
435/*---------------------------------------------------------------------------*/
443void IncrementalComponentModifier::
444_copyBetweenPartialsAndGlobals(const CopyBetweenPartialAndGlobalArgs& args)
445{
446 if (args.m_local_ids.empty())
447 return;
448 const bool do_copy = args.m_do_copy_between_partial_and_pure;
449 const bool is_add_operation = args.m_is_global_to_partial;
450 RunQueue queue(args.m_queue);
452 // Comme on a modifié des mailles, il faut mettre à jour les valeurs
453 // correspondantes pour chaque variable.
454 //info(4) << "NB_TRANSFORM=" << nb_transform << " name=" << e->name();
455 //Integer indexer_index = indexer->index();
456
457 Accelerator::RunQueuePool& queue_pool = m_material_mng->_internalApi()->asyncRunQueuePool();
458
459 // Redimensionne les variables si nécessaire
460 if (is_add_operation) {
461 _resizeVariablesIndexer(args.m_var_index);
462 }
463
464 if (do_copy) {
465 bool do_one_command = (m_use_generic_copy_between_pure_and_partial == 2);
466 UniqueArray<CopyBetweenDataInfo>& copy_data = m_work_info.m_host_variables_copy_data;
467 copy_data.clear();
468 copy_data.reserve(m_material_mng->nbVariable());
469
470 Int32 index = 0;
472 args2.m_use_generic_copy = (m_use_generic_copy_between_pure_and_partial >= 1);
473 if (do_one_command)
474 args2.m_copy_data = &copy_data;
475 auto func2 = [&](IMeshMaterialVariable* mv) {
476 auto* mvi = mv->_internalApi();
477 if (!do_one_command)
478 args2.m_queue = queue_pool[index];
479 mvi->copyBetweenPartialAndGlobal(args2);
480 ++index;
481 };
482 functor::apply(m_material_mng, &MeshMaterialMng::visitVariables, func2);
483 if (do_one_command) {
484 // Copie 'copy_data' dans le tableau correspondant pour le device éventuel.
486 m_work_info.m_variables_copy_data.copy(x, &queue);
487 _applyCopyBetweenPartialsAndGlobals(args2, queue);
488 }
489 else
490 queue_pool.barrier();
491 }
492}
493
494/*---------------------------------------------------------------------------*/
495/*---------------------------------------------------------------------------*/
496
497} // End namespace Arcane::Materials
498
499/*---------------------------------------------------------------------------*/
500/*---------------------------------------------------------------------------*/
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.
void barrier() const
Bloque tant que toutes les commandes associées à la file ne sont pas terminées.
Definition RunQueue.cc:158
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
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
Active toujours les traces dans les parties Arcane concernant les matériaux.