Sierra Toolkit  Version of the Day
BulkDataRelation.cpp
1 /*------------------------------------------------------------------------*/
2 /* Copyright 2010 Sandia Corporation. */
3 /* Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive */
4 /* license for use of this work by or on behalf of the U.S. Government. */
5 /* Export of this program may require a license from the */
6 /* United States Government. */
7 /*------------------------------------------------------------------------*/
8 
13 #include <stdexcept>
14 #include <iostream>
15 #include <sstream>
16 #include <algorithm>
17 
18 #include <stk_util/parallel/ParallelComm.hpp>
19 #include <stk_util/parallel/ParallelReduce.hpp>
20 
21 #include <stk_mesh/base/BulkData.hpp>
22 #include <stk_mesh/base/MetaData.hpp>
23 #include <stk_mesh/base/Comm.hpp>
24 #include <stk_mesh/base/FieldData.hpp>
25 #include <stk_mesh/base/Trace.hpp>
26 
27 namespace stk_classic {
28 namespace mesh {
29 
30 void set_field_relations( Entity & e_from ,
31  Entity & e_to ,
32  const unsigned ident )
33 {
34  const std::vector<FieldRelation> & field_rels =
35  MetaData::get(e_from).get_field_relations();
36 
37  for ( std::vector<FieldRelation>::const_iterator
38  j = field_rels.begin() ; j != field_rels.end() ; ++j ) {
39 
40  const FieldRelation & fr = *j ;
41 
42  void ** const ptr = (void**) field_data( * fr.m_root , e_from );
43 
44  if ( ptr ) {
45 
46  void * const src = field_data( * fr.m_target , e_to );
47 
48  const size_t number =
49  field_data_size(*fr.m_root,e_from) / sizeof(void*);
50 
51  const size_t offset =
52  (*fr.m_function)( e_from.entity_rank() ,
53  e_to.entity_rank() , ident );
54 
55  if ( offset < number ) {
56  ptr[ offset ] = src ;
57  }
58  }
59  }
60 }
61 
62 namespace {
63 
64 void clear_field_relations( Entity & e_from ,
65  const unsigned type ,
66  const unsigned ident )
67 {
68  const std::vector<FieldRelation> & field_rels =
69  MetaData::get(e_from).get_field_relations();
70 
71  for ( std::vector<FieldRelation>::const_iterator
72  j = field_rels.begin() ; j != field_rels.end() ; ++j ) {
73 
74  const FieldRelation & fr = *j ;
75 
76  void ** const ptr = (void**) field_data( * fr.m_root , e_from );
77 
78  if ( ptr ) {
79 
80  const size_t number =
81  field_data_size(*fr.m_root,e_from) / sizeof(void*);
82 
83  const size_t offset =
84  (*fr.m_function)( e_from.entity_rank() , type , ident );
85 
86  if ( offset < number ) {
87  ptr[ offset ] = NULL ;
88  }
89  }
90  }
91 }
92 
93 } // empty namespace
94 
95 //----------------------------------------------------------------------
96 
97 void BulkData::require_valid_relation( const char action[] ,
98  const BulkData & mesh ,
99  const Entity & e_from ,
100  const Entity & e_to )
101 {
102  const bool error_mesh_from = & mesh != & BulkData::get(e_from);
103  const bool error_mesh_to = & mesh != & BulkData::get(e_to);
104  const bool error_type = e_from.entity_rank() <= e_to.entity_rank();
105  const bool error_nil_from = EntityLogDeleted == e_from.log_query();
106  const bool error_nil_to = EntityLogDeleted == e_to.log_query();
107 
108  if ( error_mesh_from || error_mesh_to || error_type ||
109  error_nil_from || error_nil_to ) {
110  std::ostringstream msg ;
111 
112  msg << "Could not " << action << " relation from entity "
113  << print_entity_key(e_from) << " to entity "
114  << print_entity_key(e_to) << "\n";
115 
116  ThrowErrorMsgIf( error_mesh_from || error_mesh_to,
117  msg.str() << (error_mesh_from ? "e_from" : "e_to" ) <<
118  " not member of this mesh");
119  ThrowErrorMsgIf( error_nil_from || error_nil_to,
120  msg.str() << (error_mesh_from ? "e_from" : "e_to" ) <<
121  " was destroyed");
122  ThrowErrorMsgIf( error_type, msg.str() <<
123  "A relation must be from higher to lower ranking entity");
124  }
125 }
126 
127 //----------------------------------------------------------------------
128 
130  Entity & e_to ,
131  const RelationIdentifier local_id )
132 {
133  TraceIfWatching("stk_classic::mesh::BulkData::declare_relation", LOG_ENTITY, e_from.key());
134  TraceIfWatchingDec("stk_classic::mesh::BulkData::declare_relation", LOG_ENTITY, e_to.key(), 1);
135  DiagIfWatching(LOG_ENTITY, e_from.key(),
136  "from: " << e_from << "; " <<
137  "to: " << e_to << "; " <<
138  "id: " << local_id);
139  DiagIfWatching(LOG_ENTITY, e_to.key(),
140  "from: " << e_from << "; " <<
141  "to: " << e_to << "; " <<
142  "id: " << local_id);
143 
144  require_ok_to_modify();
145 
146  require_valid_relation( "declare" , *this , e_from , e_to );
147 
148  // TODO: Don't throw if exact relation already exists, that should be a no-op.
149  // Should be an exact match if relation of local_id already exists (e_to should be the same).
150  m_entity_repo.declare_relation( e_from, e_to, local_id, m_sync_count);
151 
152  OrdinalVector add , empty ;
153 
154  // Deduce and set new part memberships:
155 
156  induced_part_membership( e_from, empty, e_to.entity_rank(), local_id, add );
157 
158  internal_change_entity_parts( e_to , add , empty );
159 
160  set_field_relations( e_from , e_to , local_id );
161 }
162 
163 //----------------------------------------------------------------------
164 
166  const std::vector<Relation> & rel )
167 {
168  require_ok_to_modify();
169 
170  const unsigned erank = entity.entity_rank();
171 
172  std::vector<Relation>::const_iterator i ;
173  for ( i = rel.begin() ; i != rel.end() ; ++i ) {
174  Entity & e = * i->entity();
175  const unsigned n = i->identifier();
176  if ( e.entity_rank() < erank ) {
177  declare_relation( entity , e , n );
178  }
179  else if ( erank < e.entity_rank() ) {
180  declare_relation( e , entity , n );
181  }
182  else {
183  ThrowErrorMsg("Given entities of the same entity rank. entity is " <<
184  print_entity_key(entity));
185  }
186  }
187 }
188 
189 //----------------------------------------------------------------------
190 
192  Entity & e_to,
193  const RelationIdentifier local_id )
194 {
195  TraceIfWatching("stk_classic::mesh::BulkData::destroy_relation", LOG_ENTITY, e_from.key());
196  TraceIfWatchingDec("stk_classic::mesh::BulkData::destroy_relation", LOG_ENTITY, e_to.key(), 1);
197  DiagIfWatching(LOG_ENTITY, e_from.key(),
198  "from: " << e_from << "; " <<
199  "to: " << e_to << "; " <<
200  "id: " << local_id);
201  DiagIfWatching(LOG_ENTITY, e_to.key(),
202  "from: " << e_from << "; " <<
203  "to: " << e_to << "; " <<
204  "id: " << local_id);
205 
206  require_ok_to_modify();
207 
208  require_valid_relation( "destroy" , *this , e_from , e_to );
209 
210  //------------------------------
211  // When removing a relationship may need to
212  // remove part membership and set field relation pointer to NULL
213 
214  if ( parallel_size() < 2 || m_entity_comm_map.sharing(e_to.key()).empty() ) {
215 
216  //------------------------------
217  // 'keep' contains the parts deduced from kept relations
218  // 'del' contains the parts deduced from deleted relations
219  // that are not in 'keep'
220  // Only remove these part memberships the entity is not shared.
221  // If the entity is shared then wait until modificaton_end_synchronize.
222  //------------------------------
223 
224  OrdinalVector del, keep, empty;
225 
226  // For all relations that are *not* being deleted, add induced parts for
227  // these relations to the 'keep' vector
228  for ( PairIterRelation i = e_to.relations(); !i.empty(); ++i ) {
229  if (e_to.entity_rank() < i->entity_rank()) { // Need to look at back rels only
230  if ( !( i->entity() == & e_from && i->identifier() == local_id ) ) {
231  induced_part_membership( * i->entity(), empty, e_to.entity_rank(),
232  i->identifier(), keep,
233  false /*Do not look at supersets*/);
234  }
235  }
236  }
237 
238  // Find the relation this is being deleted and add the parts that are
239  // induced from that relation (and that are not in 'keep') to 'del'
240  for ( PairIterRelation i = e_from.relations() ; !i.empty() ; ++i ) {
241  if ( i->entity() == & e_to && i->identifier() == local_id ) {
242  induced_part_membership( e_from, keep, e_to.entity_rank(),
243  i->identifier(), del,
244  false /*Do not look at supersets*/);
245  clear_field_relations( e_from , e_to.entity_rank() ,
246  i->identifier() );
247  break; // at most 1 relation can match our specification
248  }
249  }
250 
251  if ( !del.empty() ) {
252  internal_change_entity_parts( e_to , empty , del );
253  }
254  }
255  else {
256  // Just clear the field, part membership will be handled by modification end
257  for ( PairIterRelation i = e_from.relations() ; !i.empty() ; ++i ) {
258  if ( i->entity() == & e_to && i->identifier() == local_id ) {
259  clear_field_relations( e_from , e_to.entity_rank() ,
260  i->identifier() );
261  break; // at most 1 relation can match our specification
262  }
263  }
264  }
265 
266  //delete relations from the entities
267  return m_entity_repo.destroy_relation( e_from, e_to, local_id);
268 }
269 
270 //----------------------------------------------------------------------
271 // Deduce propagation of part membership changes to a 'from' entity
272 // to the related 'to' entities. There can be both additions and
273 // removals.
274 
275 void BulkData::internal_propagate_part_changes(
276  Entity & entity ,
277  const PartVector & removed )
278 {
279  TraceIfWatching("stk_classic::mesh::BulkData::internal_propagate_part_changes",
280  LOG_ENTITY,
281  entity.key());
282  DiagIfWatching(LOG_ENTITY, entity.key(), "entity state: " << entity);
283  DiagIfWatching(LOG_ENTITY, entity.key(), "Removed: " << removed);
284 
285  const unsigned etype = entity.entity_rank();
286 
287  PairIterRelation rel = entity.relations();
288 
289  OrdinalVector to_del , to_add , empty ;
290 
291  for ( ; ! rel.empty() ; ++rel ) {
292  const unsigned rel_type = rel->entity_rank();
293  const unsigned rel_ident = rel->identifier();
294 
295  if ( rel_type < etype ) { // a 'to' entity
296 
297  Entity & e_to = * rel->entity();
298 
299  to_del.clear();
300  to_add.clear();
301  empty.clear();
302 
303  // Induce part membership from this relationship to
304  // pick up any additions.
305  induced_part_membership( entity, empty,
306  rel_type, rel_ident, to_add );
307 
308  if ( ! removed.empty() ) {
309  // Something was removed from the 'from' entity,
310  // deduce what may have to be removed from the 'to' entity.
311 
312  // Deduce parts for 'e_to' from all upward relations.
313  // Any non-parallel part that I removed that is not deduced for
314  // 'e_to' must be removed from 'e_to'
315 
316  for ( PairIterRelation
317  to_rel = e_to.relations(); ! to_rel.empty() ; ++to_rel ) {
318  if ( e_to.entity_rank() < to_rel->entity_rank() &&
319  & entity != to_rel->entity() /* Already did this entity */ ) {
320  // Relation from to_rel->entity() to e_to
321  induced_part_membership( * to_rel->entity(), empty,
322  e_to.entity_rank(),
323  to_rel->identifier(),
324  to_add );
325  }
326  }
327 
328  OrdinalVector::const_iterator to_add_begin = to_add.begin(),
329  to_add_end = to_add.end();
330 
331  for ( PartVector::const_iterator
332  j = removed.begin() ; j != removed.end() ; ++j ) {
333  if ( ! contains_ordinal( to_add_begin, to_add_end , (*j)->mesh_meta_data_ordinal() ) ) {
334  induced_part_membership( **j, etype, rel_type, rel_ident, to_del );
335  }
336  }
337  }
338 
339  if ( parallel_size() < 2 || m_entity_comm_map.sharing(e_to.key()).empty() ) {
340  // Entirely local, ok to remove memberships now
341  internal_change_entity_parts( e_to , to_add , to_del );
342  }
343  else {
344  // Shared, do not remove memberships now.
345  // Wait until modification_end.
346  internal_change_entity_parts( e_to , to_add , empty );
347  }
348 
349  set_field_relations( entity, e_to, rel_ident );
350  }
351  else if ( etype < rel_type ) { // a 'from' entity
352  Entity & e_from = * rel->entity();
353 
354  set_field_relations( e_from, entity, rel_ident );
355  }
356  }
357 }
358 
359 void BulkData::internal_propagate_part_changes(
360  Entity & entity ,
361  const OrdinalVector & removed )
362 {
363  TraceIfWatching("stk_classic::mesh::BulkData::internal_propagate_part_changes",
364  LOG_ENTITY,
365  entity.key());
366  DiagIfWatching(LOG_ENTITY, entity.key(), "entity state: " << entity);
367  DiagIfWatching(LOG_ENTITY, entity.key(), "Removed: " << removed);
368 
369  const unsigned etype = entity.entity_rank();
370 
371  PairIterRelation rel = entity.relations();
372 
373  OrdinalVector to_del , to_add , empty ;
374 
375  const PartVector& all_parts = m_mesh_meta_data.get_parts();
376 
377  for ( ; ! rel.empty() ; ++rel ) {
378  const unsigned rel_type = rel->entity_rank();
379  const unsigned rel_ident = rel->identifier();
380 
381  if ( rel_type < etype ) { // a 'to' entity
382 
383  Entity & e_to = * rel->entity();
384 
385  to_del.clear();
386  to_add.clear();
387  empty.clear();
388 
389  // Induce part membership from this relationship to
390  // pick up any additions.
391  induced_part_membership( entity, empty,
392  rel_type, rel_ident, to_add );
393 
394  if ( ! removed.empty() ) {
395  // Something was removed from the 'from' entity,
396  // deduce what may have to be removed from the 'to' entity.
397 
398  // Deduce parts for 'e_to' from all upward relations.
399  // Any non-parallel part that I removed that is not deduced for
400  // 'e_to' must be removed from 'e_to'
401 
402  for ( PairIterRelation
403  to_rel = e_to.relations(); ! to_rel.empty() ; ++to_rel ) {
404  if ( e_to.entity_rank() < to_rel->entity_rank() &&
405  & entity != to_rel->entity() /* Already did this entity */ ) {
406  // Relation from to_rel->entity() to e_to
407  induced_part_membership( * to_rel->entity(), empty,
408  e_to.entity_rank(),
409  to_rel->identifier(),
410  to_add );
411  }
412  }
413 
414  OrdinalVector::const_iterator to_add_begin = to_add.begin(),
415  to_add_end = to_add.end();
416 
417  for ( OrdinalVector::const_iterator
418  j = removed.begin() ; j != removed.end() ; ++j ) {
419  if ( ! contains_ordinal( to_add_begin, to_add_end , *j ) ) {
420  induced_part_membership( *all_parts[*j], etype, rel_type, rel_ident, to_del );
421  }
422  }
423  }
424 
425  if ( parallel_size() < 2 || m_entity_comm_map.sharing(e_to.key()).empty() ) {
426  // Entirely local, ok to remove memberships now
427  internal_change_entity_parts( e_to , to_add , to_del );
428  }
429  else {
430  // Shared, do not remove memberships now.
431  // Wait until modification_end.
432  internal_change_entity_parts( e_to , to_add , empty );
433  }
434 
435  set_field_relations( entity, e_to, rel_ident );
436  }
437  else if ( etype < rel_type ) { // a 'from' entity
438  Entity & e_from = * rel->entity();
439 
440  set_field_relations( e_from, entity, rel_ident );
441  }
442  }
443 }
444 
445 //----------------------------------------------------------------------
446 //----------------------------------------------------------------------
447 
448 } // namespace mesh
449 } // namespace stk_classic
450 
unsigned field_data_size(const FieldBase &f, const Bucket &k)
Size, in bytes, of the field data for each entity.
Definition: FieldData.hpp:99
void declare_relation(Entity &e_from, Entity &e_to, const RelationIdentifier local_id)
Declare a relation and its converse between entities in the same mesh.
bool destroy_relation(Entity &e_from, Entity &e_to, const RelationIdentifier local_id)
Remove all relations between two entities.
FieldTraits< field_type >::data_type * field_data(const field_type &f, const Bucket::iterator i)
Pointer to the field data array.
Definition: FieldData.hpp:116
void induced_part_membership(Part &part, unsigned entity_rank_from, unsigned entity_rank_to, RelationIdentifier relation_identifier, OrdinalVector &induced_parts, bool include_supersets)
Induce entities&#39; part membership based upon relationships between entities. Insert the result into &#39;i...
Definition: Relation.cpp:211
const EntityKey & key() const
The globally unique key ( entity type + identifier ) of this entity.
Definition: Entity.hpp:138
unsigned parallel_size() const
Size of the parallel machine.
Definition: BulkData.hpp:82
PairIterRelation relations() const
All Entity relations for which this entity is a member. The relations are ordered from lowest entity-...
Definition: Entity.hpp:161
A fundamental unit within the discretization of a problem domain, including but not limited to nodes...
Definition: Entity.hpp:120
Sierra Toolkit.
EntityRank entity_rank() const
The rank of this entity.
Definition: Entity.hpp:128
EntityId identifier() const
Identifier for this entity which is globally unique for a given entity type.
Definition: Entity.hpp:133
std::vector< Part *> PartVector
Collections of parts are frequently maintained as a vector of Part pointers.
Definition: Types.hpp:31