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