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