Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
MeshMaterialVariableIndexer.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/* MeshMaterialVariableIndexer.cc (C) 2000-2024 */
9/* */
10/* Indexer pour les variables materiaux. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ITraceMng.h"
15#include "arcane/utils/ValueChecker.h"
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/ArgumentException.h"
18#include "arcane/utils/NotSupportedException.h"
19#include "arcane/utils/PlatformUtils.h"
20#include "arcane/utils/ValueConvert.h"
21#include "arcane/utils/MemoryUtils.h"
22
23#include "arcane/materials/internal/MeshMaterialVariableIndexer.h"
24#include "arcane/materials/internal/ComponentItemListBuilder.h"
25#include "arcane/materials/internal/ConstituentModifierWorkInfo.h"
26
27#include "arcane/accelerator/Filter.h"
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
33
34namespace Arcane::Materials
35{
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39MeshMaterialVariableIndexer::
40MeshMaterialVariableIndexer(ITraceMng* tm, const String& name)
41: TraceAccessor(tm)
42, m_name(name)
43, m_matvar_indexes(platform::getAcceleratorHostMemoryAllocator())
44, m_local_ids(platform::getAcceleratorHostMemoryAllocator())
45{
46 _init();
47 m_matvar_indexes.setDebugName(String("VariableIndexerMatVarIndexes")+name);
48 m_local_ids.setDebugName(String("VariableIndexerLocalIdsIndexes")+name);
49}
50
51/*---------------------------------------------------------------------------*/
52/*---------------------------------------------------------------------------*/
53
54/*---------------------------------------------------------------------------*/
55/*---------------------------------------------------------------------------*/
56
57void MeshMaterialVariableIndexer::
58_init()
59{
60 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_PRINT_USELESS_TRANSFORMATION", true))
61 m_is_print_useless_transform = (v.value() != 0);
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67void MeshMaterialVariableIndexer::
68endUpdate(const ComponentItemListBuilderOld& builder)
69{
70 ConstArrayView<MatVarIndex> pure_matvar = builder.pureMatVarIndexes();
71 ConstArrayView<MatVarIndex> partial_matvar = builder.partialMatVarIndexes();
72
73 Integer nb_pure = pure_matvar.size();
74 Integer nb_partial = partial_matvar.size();
75 m_matvar_indexes.resize(nb_pure + nb_partial);
76
77 m_matvar_indexes.subView(0, nb_pure).copy(pure_matvar);
78 m_matvar_indexes.subView(nb_pure, nb_partial).copy(partial_matvar);
79
80 Int32ConstArrayView local_ids_in_multiple = builder.partialLocalIds();
81
82 {
83 m_local_ids.resize(nb_pure + nb_partial);
84 Integer index = 0;
85 for (Integer i = 0, n = nb_pure; i < n; ++i) {
86 m_local_ids[index] = pure_matvar[i].valueIndex();
87 ++index;
88 }
89 for (Integer i = 0, n = nb_partial; i < n; ++i) {
90 m_local_ids[index] = local_ids_in_multiple[i];
91 ++index;
92 }
93 }
94
95 // NOTE: a priori, ici on est sur que m_max_index_in_multiple_array vaut
96 // nb_partial+1
97 {
98 Int32 max_index_in_multiple = (-1);
99 for (Integer i = 0; i < nb_partial; ++i) {
100 max_index_in_multiple = math::max(partial_matvar[i].valueIndex(), max_index_in_multiple);
101 }
102 m_max_index_in_multiple_array = max_index_in_multiple;
103 }
104
105 info(4) << "END_UPDATE max_index=" << m_max_index_in_multiple_array;
106}
107
108/*---------------------------------------------------------------------------*/
109/*---------------------------------------------------------------------------*/
110
111void MeshMaterialVariableIndexer::
112endUpdateAdd(const ComponentItemListBuilder& builder, RunQueue& queue)
113{
114 SmallSpan<const Int32> pure_indexes = builder.pureIndexes();
115 SmallSpan<const Int32> partial_indexes = builder.partialIndexes();
116
117 Integer nb_pure_to_add = pure_indexes.size();
118 Integer nb_partial_to_add = partial_indexes.size();
119 Integer total_to_add = nb_pure_to_add + nb_partial_to_add;
120 Integer current_nb_item = nbItem();
121 const Int32 new_size = current_nb_item + total_to_add;
122
123 MemoryUtils::checkResizeArrayWithCapacity(m_matvar_indexes, new_size, false);
124 MemoryUtils::checkResizeArrayWithCapacity(m_local_ids, new_size, false);
125
126 SmallSpan<const Int32> local_ids_in_multiple = builder.partialLocalIds();
127 SmallSpan<Int32> local_ids_view = m_local_ids.subView(current_nb_item, total_to_add);
128 SmallSpan<MatVarIndex> matvar_indexes = m_matvar_indexes.subView(current_nb_item, total_to_add);
129
130 Int32 max_index_in_multiple = m_max_index_in_multiple_array;
131 {
132 auto command = makeCommand(queue);
133 Arcane::Accelerator::ReducerMax2<Int32> max_index_reducer(command);
134 Int32 max_to_add = math::max(nb_pure_to_add, nb_partial_to_add);
135 const Int32 component_index = m_index + 1;
136 command << RUNCOMMAND_LOOP1(iter, max_to_add, max_index_reducer)
137 {
138 auto [i] = iter();
139 if (i < nb_pure_to_add) {
140 Int32 index = pure_indexes[i];
141 local_ids_view[i] = index;
142 matvar_indexes[i] = MatVarIndex(0, index);
143 }
144 if (i < nb_partial_to_add) {
145 Int32 index = partial_indexes[i];
146 local_ids_view[nb_pure_to_add + i] = local_ids_in_multiple[i];
147 matvar_indexes[nb_pure_to_add + i] = MatVarIndex(component_index, index);
148 max_index_reducer.combine(index);
149 }
150 };
151 max_index_in_multiple = math::max(max_index_reducer.reducedValue(), m_max_index_in_multiple_array);
152 }
153 m_max_index_in_multiple_array = max_index_in_multiple;
154
155 info(4) << "END_UPDATE_ADD max_index=" << m_max_index_in_multiple_array
156 << " nb_partial_to_add=" << nb_partial_to_add;
157}
158
159/*---------------------------------------------------------------------------*/
160/*---------------------------------------------------------------------------*/
161
162void MeshMaterialVariableIndexer::
163endUpdateRemove(ConstituentModifierWorkInfo& work_info, Integer nb_remove, RunQueue& queue)
164{
165 endUpdateRemoveV2(work_info, nb_remove, queue);
166}
167
168/*---------------------------------------------------------------------------*/
169/*---------------------------------------------------------------------------*/
170
171void MeshMaterialVariableIndexer::
172endUpdateRemoveV2(ConstituentModifierWorkInfo& work_info, Integer nb_remove, RunQueue& queue)
173{
174 if (nb_remove == 0)
175 return;
176
177 Integer nb_item = nbItem();
178 Integer orig_nb_item = nb_item;
179
180 info(4) << "EndUpdateRemoveV2 nb_remove=" << nb_remove << " nb_item=" << nb_item;
181
182 if (nb_remove == nb_item) {
183 m_matvar_indexes.clear();
184 m_local_ids.clear();
185 return;
186 }
187
188 bool is_device = isAcceleratorPolicy(queue.executionPolicy());
189 auto saved_matvar_indexes_modifier = work_info.m_saved_matvar_indexes.modifier(is_device);
190 auto saved_local_ids_modifier = work_info.m_saved_local_ids.modifier(is_device);
191
192 saved_matvar_indexes_modifier.resize(nb_remove);
193 saved_local_ids_modifier.resize(nb_remove);
194
195 Accelerator::GenericFilterer filterer(queue);
196 SmallSpan<const bool> removed_cells = work_info.removedCells();
197 Span<MatVarIndex> last_matvar_indexes(saved_matvar_indexes_modifier.view());
198 Span<Int32> last_local_ids(saved_local_ids_modifier.view());
199 Span<Int32> local_ids(m_local_ids);
200 Span<MatVarIndex> matvar_indexes(m_matvar_indexes);
201
202 // Conserve \a nb_remove valeurs en partant de la fin de la liste
203 {
204 Int32 last_index = nb_item - 1;
205 auto select_lambda = [=] ARCCORE_HOST_DEVICE(Int32 index) -> bool {
206 Int32 lid = local_ids[last_index - index];
207 return !removed_cells[lid];
208 };
209 auto setter_lambda = [=] ARCCORE_HOST_DEVICE(Int32 input_index, Int32 output_index) {
210 Int32 true_index = (last_index - input_index);
211 if (output_index < nb_remove) {
212 last_matvar_indexes[output_index] = matvar_indexes[true_index];
213 last_local_ids[output_index] = local_ids[true_index];
214 }
215 };
216 filterer.applyWithIndex(orig_nb_item, select_lambda, setter_lambda, A_FUNCINFO);
217 filterer.nbOutputElement();
218 }
219
220 // Remplit les trous des mailles supprimées avec les derniers éléments de la liste
221 {
222 auto select_lambda = [=] ARCCORE_HOST_DEVICE(Int32 index) -> bool {
223 Int32 lid = local_ids[index];
224 return removed_cells[lid];
225 };
226 auto setter_lambda = [=] ARCCORE_HOST_DEVICE(Int32 input_index, Int32 output_index) {
227 matvar_indexes[input_index] = last_matvar_indexes[output_index];
228 local_ids[input_index] = last_local_ids[output_index];
229 };
230 filterer.applyWithIndex(orig_nb_item - nb_remove, select_lambda, setter_lambda, A_FUNCINFO);
231 filterer.nbOutputElement();
232 }
233 nb_item -= nb_remove;
234 m_matvar_indexes.resize(nb_item);
235 m_local_ids.resize(nb_item);
236
237 // Vérifie qu'on a bien supprimé autant d'entité que prévu.
238 Integer nb_remove_computed = (orig_nb_item - nb_item);
239 if (nb_remove_computed != nb_remove)
240 ARCANE_FATAL("Bad number of removed material items expected={0} v={1} name={2}",
241 nb_remove, nb_remove_computed, name());
242 info(4) << "END_UPDATE_REMOVE nb_removed=" << nb_remove;
243
244 // TODO: il faut recalculer m_max_index_in_multiple_array
245 // et compacter éventuellement les variables. (pas indispensable)
246}
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
251void MeshMaterialVariableIndexer::
252changeLocalIds(Int32ConstArrayView old_to_new_ids)
253{
254 this->_changeLocalIdsV2(this, old_to_new_ids);
255}
256
257/*---------------------------------------------------------------------------*/
258/*---------------------------------------------------------------------------*/
259
260void MeshMaterialVariableIndexer::
261_changeLocalIdsV2(MeshMaterialVariableIndexer* var_indexer, Int32ConstArrayView old_to_new_ids)
262{
263 // Nouvelle version du changement des localId() qui ne modifie pas l'ordre
264 // des m_matvar_indexes.
265
266 ITraceMng* tm = var_indexer->traceMng();
267
268 tm->info(4) << "ChangeLocalIdsV2 name=" << var_indexer->name();
269 // Il faut recopier le tableau des localId() car il va être modifié.
270 UniqueArray<Int32> ids_copy(var_indexer->localIds());
271 UniqueArray<MatVarIndex> matvar_indexes_copy(var_indexer->matvarIndexes());
272
273 var_indexer->m_local_ids.clear();
274 var_indexer->m_matvar_indexes.clear();
275
276 Integer nb = ids_copy.size();
277
278 tm->info(4) << "-- -- BEGIN_PROCESSING N=" << ids_copy.size();
279
280 for (Integer i = 0; i < nb; ++i) {
281 Int32 lid = ids_copy[i];
282 Int32 new_lid = old_to_new_ids[lid];
283 tm->info(5) << "I=" << i << " lid=" << lid << " new_lid=" << new_lid;
284
285 if (new_lid != NULL_ITEM_LOCAL_ID) {
286 MatVarIndex mvi = matvar_indexes_copy[i];
287 tm->info(5) << "I=" << i << " new_lid=" << new_lid << " mv=" << mvi;
288 Int32 value_index = mvi.valueIndex();
289 if (mvi.arrayIndex() == 0) {
290 // TODO: Vérifier si value_index, qui contient le localId() de l'entité
291 // ne dois pas être modifié.
292 // Normalement, il faudra avoir:
293 // value_index = new_lid;
294 // Mais cela plante actuellement car comme on ne récupère pas
295 // l'évènement executeReduce() sur les groupes il est possible
296 // que nous n'ayons pas les bons ids. (C'est quand même bizarre...)
297
298 // Variable globale: met à jour le localId() dans le MatVarIndex.
299 var_indexer->m_matvar_indexes.add(MatVarIndex(0, value_index));
300 var_indexer->m_local_ids.add(value_index);
301 }
302 else {
303 // Valeur partielle: rien ne change dans le MatVarIndex
304 var_indexer->m_matvar_indexes.add(mvi);
305 var_indexer->m_local_ids.add(new_lid);
306 }
307 }
308 }
309
310 // TODO: remplir la fin des tableaux avec des valeurs invalides (pour détecter les problèmes)
311 tm->info(4) << "-- -- ChangeLocalIdsV2 END_PROCESSING (V4)"
312 << " indexer_name=" << var_indexer->name()
313 << " nb_ids=" << var_indexer->m_local_ids.size();
314}
315
316/*---------------------------------------------------------------------------*/
317/*---------------------------------------------------------------------------*/
318/*!
319 * \brief Transforme des mailles entre pure et partielle.
320 *
321 * Les mailles à transformer sont celles pour lesquelles
322 * work_info.transformedCells() est vrai.
323 *
324 * En retour, remplit \a work_info.pure_local_ids et \a work_info.partial_indexes
325 * avec les valeurs des transformées. Si \a work_info.isAdd() est vrai,
326 * alors on transforme de pure en partial, sinon on transforme de partiel en
327 * pure.
328 * Si \a is_from_env est vrai, alors cette méthode est appelée depuis une mise
329 * à jour des milieux. Sinon c'est depuis une mise à jour des matériaux. Cela
330 * n'est utile que pour le debug.
331 */
332void MeshMaterialVariableIndexer::
333transformCells(ConstituentModifierWorkInfo& work_info, RunQueue& queue,bool is_from_env)
334{
335 bool is_pure_to_partial = work_info.isAdd();
336 bool is_device = isAcceleratorPolicy(queue.executionPolicy());
337
338 Integer nb = nbItem();
339 auto pure_local_ids_modifier = work_info.pure_local_ids.modifier(is_device);
340 auto partial_indexes_modifier = work_info.partial_indexes.modifier(is_device);
341 pure_local_ids_modifier.resize(nb);
342 partial_indexes_modifier.resize(nb);
343
344 SmallSpan<Int32> pure_local_ids = pure_local_ids_modifier.view();
345 SmallSpan<Int32> partial_indexes = partial_indexes_modifier.view();
346 SmallSpan<MatVarIndex> matvar_indexes = m_matvar_indexes.view();
347 SmallSpan<Int32> local_ids = m_local_ids.view();
348 SmallSpan<const bool> transformed_cells = work_info.transformedCells();
349
350 Accelerator::GenericFilterer filterer(queue);
351
352 if (is_pure_to_partial) {
353 // Transformation Pure -> Partial
354 auto select_lambda = [=] ARCCORE_HOST_DEVICE(Int32 index) -> bool {
355 MatVarIndex mvi = matvar_indexes[index];
356 if (mvi.arrayIndex() != 0)
357 return false;
358 Int32 local_id = local_ids[index];
359 bool do_transform = transformed_cells[local_id];
360 return do_transform;
361 };
362
363 Int32 max_index_in_multiple_array = m_max_index_in_multiple_array + 1;
364 const Int32 var_index = m_index + 1;
365 auto setter_lambda = [=] ARCCORE_HOST_DEVICE(Int32 input_index, Int32 output_index) {
366 Int32 current_index = max_index_in_multiple_array + output_index;
367 Int32 local_id = local_ids[input_index];
368 pure_local_ids[output_index] = local_id;
369 partial_indexes[output_index] = current_index;
370 matvar_indexes[input_index] = MatVarIndex(var_index, current_index);
371 };
372 filterer.applyWithIndex(nb, select_lambda, setter_lambda,
373 A_FUNCINFO1("ConstituentsTranformCellsFromPureToPartial"));
374 }
375 else {
376 // Transformation Partial -> Pure
377 auto select_lambda = [=] ARCCORE_HOST_DEVICE(Int32 index) -> bool {
378 MatVarIndex mvi = matvar_indexes[index];
379 if (mvi.arrayIndex() == 0)
380 return false;
381 Int32 local_id = local_ids[index];
382 bool do_transform = transformed_cells[local_id];
383 return do_transform;
384 };
385 auto setter_lambda = [=] ARCCORE_HOST_DEVICE(Int32 input_index, Int32 output_index) {
386 MatVarIndex mvi = matvar_indexes[input_index];
387 Int32 local_id = local_ids[input_index];
388 Int32 var_index = mvi.valueIndex();
389 pure_local_ids[output_index] = local_id;
390 partial_indexes[output_index] = var_index;
391 matvar_indexes[input_index] = MatVarIndex(0, local_id);
392 };
393 filterer.applyWithIndex(nb, select_lambda, setter_lambda,
394 A_FUNCINFO1("ConstituentsTranformCellsFromPartialToPure"));
395 }
396
397 const Int32 nb_out = filterer.nbOutputElement();
398 pure_local_ids_modifier.resize(nb_out);
399 partial_indexes_modifier.resize(nb_out);
400
401 ++m_nb_transform_called;
402
403 // Normalement la liste retournée ne devrait pas être vide.
404 // Si c'est le cas, cela signifie que l'appel à cette méthode était inutile et que
405 // le calcul des constituants modifiés (via ConstituentConnectivityList::fillModifiedConstituents())
406 // était trop permissif.
407 if (nb_out == 0) {
408 if (is_pure_to_partial)
409 ++m_nb_useless_add_transform;
410 else
411 ++m_nb_useless_remove_transform;
412 if (m_is_print_useless_transform)
413 info() << "VarIndex null transformation modified_name=" << name()
414 << " is_add=" << is_pure_to_partial << " is_from_env=" << is_from_env;
415 }
416
417 if (is_pure_to_partial)
418 m_max_index_in_multiple_array += nb_out;
419}
420
421/*---------------------------------------------------------------------------*/
422/*---------------------------------------------------------------------------*/
423
424void MeshMaterialVariableIndexer::
425checkValid()
426{
427 ValueChecker vc(A_FUNCINFO);
428
429 Integer nb_item = nbItem();
430
431 vc.areEqual(nb_item, m_matvar_indexes.size(), "Incoherent size for local ids and matvar indexes");
432
433 // TODO: vérifier que les m_local_ids pour les parties pures correspondent
434 // au m_matvar_indexes.valueIndex() correspondant.
435}
436
437/*---------------------------------------------------------------------------*/
438/*---------------------------------------------------------------------------*/
439
440void MeshMaterialVariableIndexer::
441dumpStats() const
442{
443 if (m_nb_transform_called == 0)
444 return;
445 Int32 nb_useless_call = m_nb_useless_add_transform + m_nb_useless_remove_transform;
446 Int32 nb_useful_call = m_nb_transform_called - nb_useless_call;
447 info() << "VariableIndexer name=" << name()
448 << " nb_useful_transform=" << nb_useful_call
449 << " nb_useless_add=" << m_nb_useless_add_transform
450 << " nb_useless_remove=" << m_nb_useless_remove_transform;
451}
452
453/*---------------------------------------------------------------------------*/
454/*---------------------------------------------------------------------------*/
455
456} // End namespace Arcane::Materials
457
458/*---------------------------------------------------------------------------*/
459/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Types et fonctions pour gérer les synchronisations sur les accélérateurs.
Types et macros pour gérer les boucles sur les accélérateurs.
#define RUNCOMMAND_LOOP1(iter_name, x1,...)
Boucle sur accélérateur avec arguments supplémentaires pour les réductions.
RunCommand makeCommand(const RunQueue &run_queue)
Créé une commande associée à la file run_queue.
bool isAcceleratorPolicy(eExecutionPolicy exec_policy)
Indique si exec_policy correspond à un accélérateur.
Active toujours les traces dans les parties Arcane concernant les matériaux.
IMemoryAllocator * getAcceleratorHostMemoryAllocator()
Allocateur spécifique pour les accélérateurs.
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:640
Int32 Integer
Type représentant un entier.