Arcane  v3.14.10.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-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/* ItemGroupInternal.cc (C) 2000-2024 */
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}
133
134/*---------------------------------------------------------------------------*/
135/*---------------------------------------------------------------------------*/
136
137ItemInternalList ItemGroupInternal::
138items() const
139{
140 if (m_item_family)
141 return m_item_family->itemsInternal();
142 return m_mesh->itemsInternal(m_kind);
143}
144
145/*---------------------------------------------------------------------------*/
146/*---------------------------------------------------------------------------*/
147
148Int32 ItemGroupInternal::
149maxLocalId() const
150{
151 return m_item_family->maxLocalId();
152}
153
154/*---------------------------------------------------------------------------*/
155/*---------------------------------------------------------------------------*/
156
157ItemInfoListView ItemGroupInternal::
158itemInfoListView() const
159{
160 if (m_item_family)
161 return m_item_family->itemInfoListView();
162 return m_mesh->itemFamily(m_kind)->itemInfoListView();
163}
164
165/*---------------------------------------------------------------------------*/
166/*---------------------------------------------------------------------------*/
167
168void ItemGroupInternal::
169resetSubGroups()
170{
171 if (!m_is_all_items)
172 ARCANE_FATAL("Call to _resetSubGroups() is only valid for group of AllItems");
173
174 m_own_group = nullptr;
175 m_ghost_group = nullptr;
176 m_interface_group = nullptr;
177 m_node_group = nullptr;
178 m_edge_group = nullptr;
179 m_face_group = nullptr;
180 m_cell_group = nullptr;
181 m_inner_face_group = nullptr;
182 m_outer_face_group = nullptr;
183 m_active_cell_group = nullptr;
184 m_own_active_cell_group = nullptr;
185 m_active_face_group = nullptr;
186 m_own_active_face_group = nullptr;
187 m_inner_active_face_group = nullptr;
188 m_outer_active_face_group = nullptr;
189 m_level_cell_group.clear();
190 m_own_level_cell_group.clear();
191 m_children_by_type.clear();
192 m_children_by_type_ids.clear();
193 m_sub_groups.clear();
194}
195
196/*---------------------------------------------------------------------------*/
197/*---------------------------------------------------------------------------*/
198
199void ItemGroupInternal::
200notifyExtendObservers(const Int32ConstArrayView * info)
201{
202 ARCANE_ASSERT((!m_need_recompute || m_is_all_items),("Operation on invalid group"));
203 for( const auto& i : m_observers ) {
204 IItemGroupObserver * obs = i.second;
205 obs->executeExtend(info);
206 }
207 if (m_group_index_table.isUsed())
208 m_group_index_table->update();
209}
210
211/*---------------------------------------------------------------------------*/
212/*---------------------------------------------------------------------------*/
213
214void ItemGroupInternal::
215notifyReduceObservers(const Int32ConstArrayView * info)
216{
217 ARCANE_ASSERT((!m_need_recompute || m_is_all_items),("Operation on invalid group"));
218 for( const auto& i : m_observers ) {
219 IItemGroupObserver * obs = i.second;
220 obs->executeReduce(info);
221 }
222 if (m_group_index_table.isUsed())
223 m_group_index_table->update();
224}
225
226/*---------------------------------------------------------------------------*/
227/*---------------------------------------------------------------------------*/
228
229void ItemGroupInternal::
230notifyCompactObservers(const Int32ConstArrayView * info)
231{
232 ARCANE_ASSERT((!m_need_recompute || m_is_all_items),("Operation on invalid group"));
233 for( const auto& i : m_observers ) {
234 IItemGroupObserver * obs = i.second;
235 obs->executeCompact(info);
236 }
237 if (m_group_index_table.isUsed())
238 m_group_index_table->compact(info);
239}
240
241/*---------------------------------------------------------------------------*/
242/*---------------------------------------------------------------------------*/
243
244void ItemGroupInternal::
245notifyInvalidateObservers()
246{
247#ifndef NO_USER_WARNING
248#warning "(HP) Assertion need fix"
249#endif /* NO_USER_WARNING */
250 // Cela peut se produire en cas d'invalidation en cascade
251 // ARCANE_ASSERT((!m_need_recompute),("Operation on invalid group"));
252 for( const auto& i : m_observers ) {
253 IItemGroupObserver * obs = i.second;
254 obs->executeInvalidate();
255 }
256 if (m_group_index_table.isUsed())
257 m_group_index_table->update();
258}
259
260/*---------------------------------------------------------------------------*/
261/*---------------------------------------------------------------------------*/
262/*!
263 * \brief Vérifie que les localIds() sont contigüs.
264 */
265void ItemGroupInternal::
266checkIsContigous()
267{
268 m_is_contigous = false;
269 Int32ConstArrayView lids = itemsLocalId();
270 if (lids.empty()){
271 m_is_contigous = false;
272 return;
273 }
274 Int32 first_lid = lids[0];
275
276 bool is_bad = false;
277 for( Integer i=0, n=lids.size(); i<n; ++i ){
278 if (lids[i]!=(first_lid+i)){
279 is_bad = true;
280 break;
281 }
282 }
283 if (!is_bad)
284 m_is_contigous = true;
285}
286
287/*---------------------------------------------------------------------------*/
288/*---------------------------------------------------------------------------*/
289
290void ItemGroupInternal::
291applySimdPadding()
292{
293 if (m_is_print_apply_simd_padding){
294 String stack;
295 if (m_is_print_stack_apply_simd_padding)
296 stack = String(" stack=") + platform::getStackTrace();
297 ITraceMng* tm = m_item_family->traceMng();
298 tm->info() << "ApplySimdPadding group_name=" << m_name << stack;
299 }
300 // Fait un padding des derniers éléments du tableau en recopiant la
301 // dernière valeurs.
302 m_internal_api.notifySimdPaddingDone();
303 Arcane::applySimdPadding(mutableItemsLocalId());
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:151
ConstArrayView< Int32 > Int32ConstArrayView
Equivalent C d'un tableau à une dimension d'entiers 32 bits.
Definition UtilsTypes.h:640
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:327
Int32 Integer
Type représentant un entier.