void FeatureFloodCount::flood(const DofObject * dof_object, unsigned long current_idx, FeatureData * feature) { if (dof_object == nullptr) return; // Retrieve the id of the current entity auto entity_id = dof_object->id(); // Has this entity already been marked? - if so move along if (_entities_visited[current_idx].find(entity_id) != _entities_visited[current_idx].end()) return; // Mark this entity as visited _entities_visited[current_idx][entity_id] = true; // Determine which threshold to use based on whether this is an established region auto threshold = feature ? _step_connecting_threshold : _step_threshold; // Get the value of the current variable for the current entity Real entity_value; if (_is_elemental) { const Elem * elem = static_cast<const Elem *>(dof_object); std::vector<Point> centroid(1, elem->centroid()); _subproblem.reinitElemPhys(elem, centroid, 0); entity_value = _vars[current_idx]->sln()[0]; } else entity_value = _vars[current_idx]->getNodalValue(*static_cast<const Node *>(dof_object)); // This node hasn't been marked, is it in a feature? We must respect // the user-selected value of _use_less_than_threshold_comparison. if (_use_less_than_threshold_comparison && (entity_value < threshold)) return; if (!_use_less_than_threshold_comparison && (entity_value > threshold)) return; /** * If we reach this point (i.e. we haven't returned early from this routine), * we've found a new mesh entity that's part of a feature. */ auto map_num = _single_map_mode ? decltype(current_idx)(0) : current_idx; // New Feature (we need to create it and add it to our data structure) if (!feature) _partial_feature_sets[map_num].emplace_back(current_idx); // Get a handle to the feature we will update (always the last feature in the data structure) feature = &_partial_feature_sets[map_num].back(); // Insert the current entity into the local ids map feature->_local_ids.insert(entity_id); if (_is_elemental) visitElementalNeighbors(static_cast<const Elem *>(dof_object), current_idx, feature, /*expand_halos_only =*/false); else visitNodalNeighbors(static_cast<const Node *>(dof_object), current_idx, feature, /*expand_halos_only =*/false); }
void GrainTracker::expandHalos() { processor_id_type n_procs = _app.n_processors(); for (unsigned int map_num = 0; map_num < _maps_size; ++map_num) for (processor_id_type rank = 0; rank < n_procs; ++rank) for (std::vector<FeatureData>::iterator it = _partial_feature_sets[rank][map_num].begin(); it != _partial_feature_sets[rank][map_num].end(); ++it) { FeatureData & feature = *it; for (unsigned int halo_level = 1; halo_level < _halo_level; ++halo_level) { /** * Create a copy of the halo set so that as we insert new ids into the * set we don't continue to iterate on those new ids. */ std::set<dof_id_type> orig_halo_ids(feature._halo_ids); for (std::set<dof_id_type>::iterator entity_it = orig_halo_ids.begin(); entity_it != orig_halo_ids.end(); ++entity_it) { if (_is_elemental) visitElementalNeighbors(_mesh.elemPtr(*entity_it), feature._var_idx, &feature, /*recurse =*/false); else visitNodalNeighbors(_mesh.nodePtr(*entity_it), feature._var_idx, &feature, /*recurse =*/false); } } } }
void FeatureFloodCount::flood(const DofObject * dof_object, std::size_t current_index, FeatureData * feature) { if (dof_object == nullptr) return; // Retrieve the id of the current entity auto entity_id = dof_object->id(); // Has this entity already been marked? - if so move along if (_entities_visited[current_index].find(entity_id) != _entities_visited[current_index].end()) return; // See if the current entity either starts a new feature or continues an existing feature auto new_id = invalid_id; // Writable reference to hold an optional id; if (!isNewFeatureOrConnectedRegion(dof_object, current_index, feature, new_id)) return; /** * If we reach this point (i.e. we haven't returned early from this routine), * we've found a new mesh entity that's part of a feature. We need to mark * the entity as visited at this point (and not before!) to avoid infinite * recursion. If you mark the node too early you risk not coloring in a whole * feature any time a "connecting threshold" is used since we may have * already visited this entity earlier but it was in-between two thresholds. */ _entities_visited[current_index][entity_id] = true; auto map_num = _single_map_mode ? decltype(current_index)(0) : current_index; // New Feature (we need to create it and add it to our data structure) if (!feature) { _partial_feature_sets[map_num].emplace_back(current_index, _feature_count++, processor_id()); // Get a handle to the feature we will update (always the last feature in the data structure) feature = &_partial_feature_sets[map_num].back(); // If new_id is valid, we'll set it in the feature here. if (new_id != invalid_id) feature->_id = new_id; } // Insert the current entity into the local ids map feature->_local_ids.insert(entity_id); /** * See if this particular entity cell contributes to the centroid calculation. We * only deal with elemental floods and only count it if it's owned by the current * processor to avoid skewing the result. */ if (_is_elemental && processor_id() == dof_object->processor_id()) { const Elem * elem = static_cast<const Elem *>(dof_object); // Keep track of how many elements participate in the centroid averaging feature->_vol_count++; // Sum the centroid values for now, we'll average them later feature->_centroid += elem->centroid(); // Does the volume intersect the boundary? if (_all_boundary_entity_ids.find(elem->id()) != _all_boundary_entity_ids.end()) feature->_intersects_boundary = true; } if (_is_elemental) visitElementalNeighbors(static_cast<const Elem *>(dof_object), current_index, feature, /*expand_halos_only =*/false); else visitNodalNeighbors(static_cast<const Node *>(dof_object), current_index, feature, /*expand_halos_only =*/false); }