Arcane  4.2.1.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
ItemGroupInternal.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 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/* ItemGroupInternal.cc (C) 2000-2026 */
9/* */
10/* Partie interne à Arcane de ItemGroup. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/core/internal/ItemGroupInternal.h"
15
16#include "arcane/utils/PlatformUtils.h"
17#include "arcane/utils/ITraceMng.h"
18#include "arcane/utils/ArrayUtils.h"
19#include "arcane/utils/ArgumentException.h"
20#include "arcane/utils/Convert.h"
21
22#include "arcane/core/ItemGroupObserver.h"
23#include "arcane/core/IItemFamily.h"
24#include "arcane/core/IMesh.h"
25#include "arcane/core/ItemPrinter.h"
26#include "arcane/core/MeshPartInfo.h"
28#include "arcane/core/internal/IDataInternal.h"
29
30/*---------------------------------------------------------------------------*/
31/*---------------------------------------------------------------------------*/
32
33namespace Arcane
34{
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
39ItemGroupInternal::
40ItemGroupInternal()
41: m_internal_api(this)
42, m_sub_parts_by_type(this)
43{
44 _init();
45}
46
47/*---------------------------------------------------------------------------*/
48/*---------------------------------------------------------------------------*/
49
50ItemGroupInternal::
51ItemGroupInternal(IItemFamily* family, const String& name)
52: m_internal_api(this)
53, m_mesh(family->mesh())
54, m_item_family(family)
55, m_variable_name(String("GROUP_") + family->name() + name)
56, m_is_null(false)
57, m_kind(family->itemKind())
58, m_name(name)
59, m_sub_parts_by_type(this)
60{
61 _init();
62}
63
64/*---------------------------------------------------------------------------*/
65/*---------------------------------------------------------------------------*/
66
67ItemGroupInternal::
68ItemGroupInternal(IItemFamily* family, ItemGroupImpl* parent, const String& name)
69: m_internal_api(this)
70, m_mesh(parent->mesh())
71, m_item_family(family)
72, m_parent(parent)
73, m_variable_name(String("GROUP_") + m_item_family->name() + name)
74, m_is_null(false)
75, m_kind(family->itemKind())
76, m_name(name)
77, m_sub_parts_by_type(this)
78{
79 _init();
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
84
85ItemGroupInternal::
86~ItemGroupInternal()
87{
88 // (HP) TODO: vérifier qu'il n'y a plus d'observer à cet instant
89 // Ceux des sous-groupes n'ont pas été détruits
90 for (const auto& i : m_observers) {
91 delete i.second;
92 }
93 delete m_variable_items_local_id;
94 delete m_compute_functor;
95}
96
97/*---------------------------------------------------------------------------*/
98/*---------------------------------------------------------------------------*/
99
100void ItemGroupInternal::
101_init()
102{
103 if (m_item_family)
104 m_full_name = m_item_family->fullName() + "_" + m_name;
105
106 // Si un maillage est associé et qu'on n'est un groupe enfant alors les données du groupe
107 // sont conservées dans une variable.
108 if (m_mesh && !m_parent) {
109 int property = IVariable::PSubDomainDepend | IVariable::PPrivate;
110 VariableBuildInfo vbi(m_mesh, m_variable_name, property);
111 m_variable_items_local_id = new VariableArrayInt32(vbi);
112 m_items_local_id = &m_variable_items_local_id->_internalTrueData()->_internalDeprecatedValue();
113 updateTimestamp();
114 }
115
116 m_is_check_simd_padding = arcaneIsCheck();
117 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_CHECK_SIMDPADDING", true)) {
118 m_is_check_simd_padding = (v.value() > 0);
119 m_is_print_check_simd_padding = (v.value() > 1);
120 }
121
122 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_PRINT_APPLYSIMDPADDING", true)) {
123 m_is_print_apply_simd_padding = (v.value() > 0);
124 m_is_print_stack_apply_simd_padding = (v.value() > 1);
125 }
126
127 if (auto v = Convert::Type<Int32>::tryParseFromEnvironment("ARCANE_USE_LOCK_FOR_ITEMGROUP_UPDATE", true)) {
128 if (v.value() > 0)
129 m_check_need_update_mutex.create();
130 }
131}
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135
136ItemInternalList ItemGroupInternal::
137items() const
138{
139 if (m_item_family)
140 return m_item_family->itemsInternal();
141 return m_mesh->itemsInternal(m_kind);
142}
143
144/*---------------------------------------------------------------------------*/
145/*---------------------------------------------------------------------------*/
146
147Int32 ItemGroupInternal::
148maxLocalId() const
149{
150 return m_item_family->maxLocalId();
151}
152
153/*---------------------------------------------------------------------------*/
154/*---------------------------------------------------------------------------*/
155
156ItemInfoListView ItemGroupInternal::
157itemInfoListView() const
158{
159 if (m_item_family)
160 return m_item_family->itemInfoListView();
161 return m_mesh->itemFamily(m_kind)->itemInfoListView();
162}
163
164/*---------------------------------------------------------------------------*/
165/*---------------------------------------------------------------------------*/
166
167void ItemGroupInternal::
168resetSubGroups()
169{
170 if (!m_is_all_items)
171 ARCANE_FATAL("Call to _resetSubGroups() is only valid for group of AllItems");
172
173 m_own_group = nullptr;
174 m_ghost_group = nullptr;
175 m_interface_group = nullptr;
176 m_node_group = nullptr;
177 m_edge_group = nullptr;
178 m_face_group = nullptr;
179 m_cell_group = nullptr;
180 m_inner_face_group = nullptr;
181 m_outer_face_group = nullptr;
182 m_active_cell_group = nullptr;
183 m_own_active_cell_group = nullptr;
184 m_active_face_group = nullptr;
185 m_own_active_face_group = nullptr;
186 m_inner_active_face_group = nullptr;
187 m_outer_active_face_group = nullptr;
188 m_level_cell_group.clear();
189 m_own_level_cell_group.clear();
190 m_sub_parts_by_type.clear();
191 m_sub_groups.clear();
192}
193
194/*---------------------------------------------------------------------------*/
195/*---------------------------------------------------------------------------*/
196
197void ItemGroupInternal::
198notifyExtendObservers(const Int32ConstArrayView* info)
199{
200 ARCANE_ASSERT((!m_need_recompute || m_is_all_items), ("Operation on invalid group"));
201 for (const auto& i : m_observers) {
202 IItemGroupObserver* obs = i.second;
203 obs->executeExtend(info);
204 }
205 if (m_group_index_table.isUsed())
206 m_group_index_table->update();
207}
208
209/*---------------------------------------------------------------------------*/
210/*---------------------------------------------------------------------------*/
211
212void ItemGroupInternal::
213notifyReduceObservers(const Int32ConstArrayView* info)
214{
215 ARCANE_ASSERT((!m_need_recompute || m_is_all_items), ("Operation on invalid group"));
216 for (const auto& i : m_observers) {
217 IItemGroupObserver* obs = i.second;
218 obs->executeReduce(info);
219 }
220 if (m_group_index_table.isUsed())
221 m_group_index_table->update();
222}
223
224/*---------------------------------------------------------------------------*/
225/*---------------------------------------------------------------------------*/
226
227void ItemGroupInternal::
228notifyCompactObservers(const Int32ConstArrayView* info)
229{
230 ARCANE_ASSERT((!m_need_recompute || m_is_all_items), ("Operation on invalid group"));
231 for (const auto& i : m_observers) {
232 IItemGroupObserver* obs = i.second;
233 obs->executeCompact(info);
234 }
235 if (m_group_index_table.isUsed())
236 m_group_index_table->compact(info);
237}
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
241
242void ItemGroupInternal::
243notifyInvalidateObservers()
244{
245#ifndef NO_USER_WARNING
246#warning "(HP) Assertion need fix"
247#endif /* NO_USER_WARNING */
248 // Cela peut se produire en cas d'invalidation en cascade
249 // ARCANE_ASSERT((!m_need_recompute),("Operation on invalid group"));
250 for (const auto& i : m_observers) {
251 IItemGroupObserver* obs = i.second;
252 obs->executeInvalidate();
253 }
254 if (m_group_index_table.isUsed())
255 m_group_index_table->update();
256}
257
258/*---------------------------------------------------------------------------*/
259/*---------------------------------------------------------------------------*/
260
261/*!
262 * \brief Vérifie que les localIds() sont contigus.
263 */
264void ItemGroupInternal::
265checkIsContiguous()
266{
267 m_is_contiguous = false;
268 Int32ConstArrayView lids = itemsLocalId();
269 if (lids.empty()) {
270 m_is_contiguous = false;
271 return;
272 }
273 Int32 first_lid = lids[0];
274
275 bool is_bad = false;
276 for (Integer i = 0, n = lids.size(); i < n; ++i) {
277 if (lids[i] != (first_lid + i)) {
278 is_bad = true;
279 break;
280 }
281 }
282 if (!is_bad)
283 m_is_contiguous = true;
284}
285
286/*---------------------------------------------------------------------------*/
287/*---------------------------------------------------------------------------*/
288
289void ItemGroupInternal::
290applySimdPadding()
291{
292 if (m_is_print_apply_simd_padding) {
293 String stack;
294 if (m_is_print_stack_apply_simd_padding)
295 stack = String(" stack=") + platform::getStackTrace();
296 ITraceMng* tm = m_item_family->traceMng();
297 tm->info() << "ApplySimdPadding group_name=" << m_name << stack;
298 }
299 // Fait un padding des derniers éléments du tableau en recopiant la
300 // dernière valeurs.
301 m_internal_api.notifySimdPaddingDone();
302 Arcane::applySimdPadding(mutableItemsLocalId());
303}
304
305/*---------------------------------------------------------------------------*/
306/*---------------------------------------------------------------------------*/
307
308/*!
309 * \brief Remplit les derniers éléments du groupe pour avoir un vecteur
310 * SIMD complet.
311 *
312 * Pour que la vectorisation fonctionne il faut que le nombre d'éléments
313 * du groupe soit un multiple de la taille d'un vecteur SIMD. Si ce n'est
314 * pas le cas, on remplit les dernières valeurs du tableau des localId()
315 * avec le dernier élément.
316 *
317 * Par exemple, on supporse une taille d'un vecteur SIMD de 8 (ce qui est le maximum
318 * actuellement avec l'AVX512) et un groupe \a grp de 13 éléments. Il faut donc
319 * remplit le groupe comme suit:
320 * \code
321 * Int32 last_local_id = grp[12];
322 * grp[13] = grp[14] = grp[15] = last_local_id.
323 * \endcode
324 *
325 * A noter que la taille du groupe reste effectivement de 13 éléments. Le
326 * padding supplémentaire n'est que pour les itérations via ENUMERATE_SIMD.
327 * Comme le tableau des localId() est alloué avec l'allocateur d'alignement
328 * il est garanti que la mémoire allouée est suffisante pour faire le padding.
329 *
330 * \todo Ne pas faire cela dans tous les checkNeedUpdate() mais mettre
331 * en place une méthode qui retourne un énumérateur spécifique pour
332 * la vectorisation.
333 */
334void ItemGroupInternal::
335checkUpdateSimdPadding()
336{
337 if (m_simd_timestamp >= timestamp()) {
338 // Vérifie que le padding est bon
339 if (m_is_check_simd_padding) {
340 if (m_is_print_check_simd_padding && m_item_family) {
341 ITraceMng* tm = m_item_family->traceMng();
342 tm->info() << "check padding name=" << fullName()
343 << " timestamp=" << timestamp()
344 << " simd_timestamp=" << m_simd_timestamp
345 << " size=" << mutableItemsLocalId().size()
346 << " capacity=" << mutableItemsLocalId().capacity();
347 }
348 ArrayUtils::checkSimdPadding(itemsLocalId());
349 }
350 return;
351 }
352 this->applySimdPadding();
353}
354
355/*---------------------------------------------------------------------------*/
356/*---------------------------------------------------------------------------*/
357
358void ItemGroupInternal::
359_removeItems(SmallSpan<const Int32> items_local_id)
360{
361 if (!((!m_need_recompute && !isAllItems()) || (m_transaction_mode && isAllItems())))
362 ARCANE_FATAL("Operation on invalid group");
363
364 if (m_compute_functor && !m_transaction_mode)
365 ARCANE_FATAL("Cannot remove items on computed group ({0})", name());
366
367 IMesh* amesh = mesh();
368 if (!amesh)
369 throw ArgumentException(A_FUNCINFO, "null group");
370
371 ITraceMng* trace = amesh->traceMng();
372 if (isOwn() && amesh->meshPartInfo().nbPart() != 1)
373 ARCANE_THROW(NotSupportedException, "Cannot remove items if isOwn() is true");
374
375 Int32 nb_item_to_remove = items_local_id.size();
376
377 // N'est utile que si on a des observers
378 UniqueArray<Int32> removed_local_ids;
379
380 if (nb_item_to_remove != 0) { // on ne peut tout de même pas faire de retour anticipé à cause des observers
381
382 Int32Array& items_lid = mutableItemsLocalId();
383 const Int32 old_size = items_lid.size();
384 bool has_removed = false;
385
386 if (isAllItems()) {
387 // Algorithme anciennement dans DynamicMeshKindInfo
388 // Supprime des items du groupe all_items par commutation avec les
389 // éléments de fin de ce groupe
390 // ie memoire persistante O(size groupe), algo O(remove items)
391 has_removed = true;
392 Integer nb_item = old_size;
393 for (Integer i = 0, n = nb_item_to_remove; i < n; ++i) {
394 Int32 removed_local_id = items_local_id[i];
395 Int32 index = m_items_index_in_all_group[removed_local_id];
396 --nb_item;
397 Int32 moved_local_id = items_lid[nb_item];
398 items_lid[index] = moved_local_id;
399 m_items_index_in_all_group[moved_local_id] = index;
400 }
401 items_lid.resize(nb_item);
402 }
403 else {
404 // Algorithme pour les autres groupes
405 // Décalage de tableau
406 // ie mémoire locale O(size groupe), algo O(size groupe)
407 // Marque un tableau indiquant les entités à supprimer
408 UniqueArray<bool> remove_flags(maxLocalId(), false);
409 for (Int32 i = 0; i < nb_item_to_remove; ++i)
410 remove_flags[items_local_id[i]] = true;
411
412 {
413 Int32 next_index = 0;
414 for (Int32 i = 0; i < old_size; ++i) {
415 Int32 lid = items_lid[i];
416 if (remove_flags[lid]) {
417 removed_local_ids.add(lid);
418 continue;
419 }
420 items_lid[next_index] = lid;
421 ++next_index;
422 }
423 if (next_index != old_size) {
424 has_removed = true;
425 items_lid.resize(next_index);
426 }
427 }
428 }
429
430 updateTimestamp();
431 if (arcaneIsCheck()) {
432 trace->info(5) << "ItemGroupImpl::removeItems() group <" << name() << "> "
433 << " old_size=" << old_size
434 << " new_size=" << nbItem()
435 << " removed?=" << has_removed;
436 checkValid();
437 }
438 }
439
440 Int32ConstArrayView observation_info(removed_local_ids);
441 notifyReduceObservers(&observation_info);
442}
443
444/*---------------------------------------------------------------------------*/
445/*---------------------------------------------------------------------------*/
446
447void ItemGroupInternal::
448checkValid()
449{
450 ITraceMng* msg = mesh()->traceMng();
451 if (m_need_recompute && m_compute_functor) {
452 msg->debug(Trace::High) << "ItemGroupImpl::checkValid on " << name() << " : skip group to recompute";
453 return;
454 }
455
456 // Les points suivants sont vérifiés
457 // - une entité n'est présente qu'une fois dans le groupe
458 // - les entités du groupe ne sont pas détruites
459 UniqueArray<bool> presence_checks(maxLocalId());
460 presence_checks.fill(0);
461 Integer nb_error = 0;
462
463 ItemInternalList items(this->items());
464 Integer items_size = items.size();
465 Int32ConstArrayView items_lid(itemsLocalId());
466
467 for (Integer i = 0, is = items_lid.size(); i < is; ++i) {
468 Integer lid = items_lid[i];
469 if (lid >= items_size) {
470 if (nb_error < 10) {
471 msg->error() << "Wrong local index lid=" << lid << " max=" << items_size
472 << " var_max_size=" << maxLocalId();
473 }
474 ++nb_error;
475 continue;
476 }
477 ItemInternal* item = items[lid];
478 if (item->isSuppressed()) {
479 if (nb_error < 10) {
480 msg->error() << "Item " << ItemPrinter(item) << " in group "
481 << name() << " does not exist anymore";
482 }
483 ++nb_error;
484 }
485 if (presence_checks[lid]) {
486 if (nb_error < 10) {
487 msg->error() << "Item " << ItemPrinter(item) << " in group "
488 << name() << " was found twice or more";
489 }
490 ++nb_error;
491 }
492 presence_checks[lid] = true;
493 }
494 if (isAllItems()) {
495 for (Integer i = 0, n = items_lid.size(); i < n; ++i) {
496 Int32 local_id = items_lid[i];
497 Int32 index_in_all_group = m_items_index_in_all_group[local_id];
498 if (index_in_all_group != i) {
499 if (nb_error < 10) {
500 msg->error() << A_FUNCINFO
501 << ": " << itemKindName(m_kind)
502 << ": incoherence between 'local_id' and index in the group 'All' "
503 << " i=" << i
504 << " local_id=" << local_id
505 << " index=" << index_in_all_group;
506 }
507 ++nb_error;
508 }
509 }
510 }
511 if (nb_error != 0) {
512 String parent_name = "none";
513 if (m_parent)
514 parent_name = m_parent->name();
515 ARCANE_FATAL("Error in group name='{0}' parent='{1}' nb_error={2}",
516 name(), parent_name, nb_error);
517 }
518}
519
520/*---------------------------------------------------------------------------*/
521/*---------------------------------------------------------------------------*/
522
523void ItemGroupInternal::
524_notifyDirectRemoveItems(SmallSpan<const Int32> removed_ids, Int32 nb_remaining)
525{
526 mutableItemsLocalId().resize(nb_remaining);
527 updateTimestamp();
528 if (arcaneIsCheck())
529 checkValid();
530 // NOTE: la liste \a removed_ids n'est pas forcément dans le même ordre
531 // que celle obtenue via removeItems()
532 Int32ConstArrayView observation_info(removed_ids.smallView());
533 notifyReduceObservers(&observation_info);
534}
535
536/*---------------------------------------------------------------------------*/
537/*---------------------------------------------------------------------------*/
538
539/*---------------------------------------------------------------------------*/
540/*---------------------------------------------------------------------------*/
541
542void ItemGroupImplInternal::
543setAsConstituentGroup()
544{
545 m_p->m_is_constituent_group = true;
546}
547
548/*---------------------------------------------------------------------------*/
549/*---------------------------------------------------------------------------*/
550
551SmallSpan<Int32> ItemGroupImplInternal::
552itemsLocalId()
553{
554 return m_p->itemsLocalId();
555}
556
557/*---------------------------------------------------------------------------*/
558/*---------------------------------------------------------------------------*/
559
560void ItemGroupImplInternal::
561notifyDirectRemoveItems(SmallSpan<const Int32> removed_ids, Int32 nb_remaining)
562{
563 m_p->_notifyDirectRemoveItems(removed_ids, nb_remaining);
564}
565
566/*---------------------------------------------------------------------------*/
567/*---------------------------------------------------------------------------*/
568
569void ItemGroupImplInternal::
570notifySimdPaddingDone()
571{
572 m_p->m_simd_timestamp = m_p->timestamp();
573}
574
575/*---------------------------------------------------------------------------*/
576/*---------------------------------------------------------------------------*/
577
578void ItemGroupImplInternal::
579setMemoryRessourceForItemLocalId(eMemoryRessource mem)
580{
581 VariableArrayInt32* v = m_p->m_variable_items_local_id;
582 if (v)
583 VariableUtils::experimentalChangeAllocator(v->variable(), mem);
584}
585
586/*---------------------------------------------------------------------------*/
587/*---------------------------------------------------------------------------*/
588
589} // End namespace Arcane
590
591/*---------------------------------------------------------------------------*/
592/*---------------------------------------------------------------------------*/
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Fonctions utilitaires sur les variables.
VariableRefArrayT< Int32 > VariableArrayInt32
Variable tableau de type entier 32 bits.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
bool arcaneIsCheck()
Vrai si on est en mode vérification.
Definition Misc.cc:68
Int32 Integer
Type représentant un entier.
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:480
ConstArrayView< ItemInternal * > ItemInternalList
Type de la liste interne des entités.
Definition ItemTypes.h:466
const char * itemKindName(eItemKind kind)
Nom du genre d'entité.
Array< Int32 > Int32Array
Tableau dynamique à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:121