Arcane  v3.14.10.0
Documentation utilisateur
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/*---------------------------------------------------------------------------*/
84/*!
85 * \brief Transforme les entités pour un milieu.
86 *
87 * Parcours le milieux \a env et
88 * convertie les mailles pures en mailles partielles ou
89 * inversement. Après conversion, les valeurs correspondantes aux
90 * mailles modifiées sont mises à jour pour chaque variable.
91 *
92 * Si \a is_add est vrai, alors on transforme de pure en partiel
93 * (ajout de matériau) sinon on transforme de partiel en pure
94 * (suppression d'un matériau)
95 */
96void IncrementalComponentModifier::
97_switchCellsForMaterials(const MeshMaterial* modified_mat,
98 SmallSpan<const Int32> ids)
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/*---------------------------------------------------------------------------*/
152/*!
153 * \brief Transforme les entités pour les milieux.
154 *
155 * Parcours les milieux, sauf le milieu modifié \a modified_env et
156 * pour chacun convertie les mailles pures en mailles partielles ou
157 * inversement. Après conversion, les valeurs correspondantes aux
158 * mailles modifiées sont mises à jour pour chaque variable.
159 *
160 * Si \a is_add est vrai, alors on transforme de pure en partiel
161 * (dans le cas d'ajout de matériau) sinon on transforme de partiel
162 * en pure (dans le cas de suppression d'un matériau)
163 */
164void IncrementalComponentModifier::
165_switchCellsForEnvironments(const IMeshEnvironment* modified_env,
166 SmallSpan<const Int32> ids)
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
193 if (!is_environments_modified[env_id])
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/*---------------------------------------------------------------------------*/
230/*!
231 * \brief Calcule les mailles à transformer pour le matériau \at mat.
232 */
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/*---------------------------------------------------------------------------*/
247/*!
248 * \brief Supprime les mailles d'un matériau du milieu.
249 *
250 * Supprime les mailles données par \a local_ids du matériau \a mat
251 * du milieu. L'indexeur du matériau est mis à jour et si \a update_env_indexer
252 * est vrai, celui du milieu aussi (ce qui signifie que le milieu disparait
253 * des mailles \a local_ids).
254 *
255 * TODO: optimiser cela en ne parcourant pas toutes les mailles
256 * matériaux du milieu (il faut supprimer removed_local_ids_filter).
257 * Si on connait l'indice de chaque maille dans la liste des MatVarIndex
258 * de l'indexeur, on peut directement taper dedans.
259 */
260void IncrementalComponentModifier::
261_removeItemsFromEnvironment(MeshEnvironment* env, MeshMaterial* mat,
262 SmallSpan<const Int32> local_ids, bool update_env_indexer)
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/*---------------------------------------------------------------------------*/
284/*!
285 * \brief Ajoute les mailles d'un matériau du milieu.
286 *
287 * Ajoute les mailles données par \a local_ids au matériau \a mat
288 * du milieu. L'indexeur du matériau est mis à jour et si \a update_env_indexer
289 * est vrai, celui du milieu aussi (ce qui signifie que le milieu apparait
290 * dans les mailles \a local_ids).
291 */
292void IncrementalComponentModifier::
293_addItemsToEnvironment(MeshEnvironment* env, MeshMaterial* mat,
294 SmallSpan<const Int32> local_ids, bool update_env_indexer)
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,
326 SmallSpan<const Int32> local_ids)
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/*---------------------------------------------------------------------------*/
397/*!
398 * \brief Redimensionne l'index \a var_index des variables.
399 */
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);
406 ResizeVariableIndexerArgs resize_args(var_index, queue);
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.
426 MDSpan<CopyBetweenDataInfo, MDDim1> x(copy_data.data(), MDIndex<1>(copy_data.size()));
427 m_work_info.m_variables_copy_data.copy(x, &queue);
428 _applyCopyVariableViews(queue);
429 }
430
431 queue.barrier();
432}
433
434/*---------------------------------------------------------------------------*/
435/*---------------------------------------------------------------------------*/
436/*!
437 * \brief Copie entre les valeurs partielles et les valeurs globales.
438 *
439 * Si \a pure_to_partial est vrai, alors on copie les valeurs globales
440 * vers les valeurs partielles, sinon on fait l'inverse.
441 * de suppression d'un matériau)
442 */
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);
451 RunQueue::ScopedAsync sc(&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;
471 CopyBetweenPartialAndGlobalArgs args2(args);
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.
485 MDSpan<CopyBetweenDataInfo, MDDim1> x(copy_data.data(), MDIndex<1>(copy_data.size()));
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/*---------------------------------------------------------------------------*/
Active toujours les traces dans les parties Arcane concernant les matériaux.