Пример #1
0
  AxisAlignedBoundingBox DatabaseIO::get_bounding_box(const Ioss::ElementBlock *eb) const
  {
    if (elementBlockBoundingBoxes.empty()) {
      // Calculate the bounding boxes for all element blocks...
      std::vector<double> coordinates;
      Ioss::NodeBlock *   nb = get_region()->get_node_blocks()[0];
      nb->get_field_data("mesh_model_coordinates", coordinates);
      ssize_t nnode = nb->get_property("entity_count").get_int();
      ssize_t ndim  = nb->get_property("component_degree").get_int();

      Ioss::ElementBlockContainer element_blocks = get_region()->get_element_blocks();
      size_t                      nblock         = element_blocks.size();
      std::vector<double>         minmax;
      minmax.reserve(6 * nblock);

      for (auto &block : element_blocks) {
        double xmin, ymin, zmin, xmax, ymax, zmax;
        if (block->get_database()->int_byte_size_api() == 8) {
          std::vector<int64_t> connectivity;
          block->get_field_data("connectivity_raw", connectivity);
          calc_bounding_box(ndim, nnode, coordinates, connectivity, xmin, ymin, zmin, xmax, ymax,
                            zmax);
        }
        else {
          std::vector<int> connectivity;
          block->get_field_data("connectivity_raw", connectivity);
          calc_bounding_box(ndim, nnode, coordinates, connectivity, xmin, ymin, zmin, xmax, ymax,
                            zmax);
        }

        minmax.push_back(xmin);
        minmax.push_back(ymin);
        minmax.push_back(zmin);
        minmax.push_back(-xmax);
        minmax.push_back(-ymax);
        minmax.push_back(-zmax);
      }

      util().global_array_minmax(minmax, Ioss::ParallelUtils::DO_MIN);

      for (size_t i = 0; i < element_blocks.size(); i++) {
        Ioss::ElementBlock *   block = element_blocks[i];
        const std::string &    name  = block->name();
        AxisAlignedBoundingBox bbox(minmax[6 * i + 0], minmax[6 * i + 1], minmax[6 * i + 2],
                                    -minmax[6 * i + 3], -minmax[6 * i + 4], -minmax[6 * i + 5]);
        elementBlockBoundingBoxes[name] = bbox;
      }
    }
    return elementBlockBoundingBoxes[eb->name()];
  }
Пример #2
0
void eliminate_omitted_nodes(RegionVector &part_mesh,
			     std::vector<INT> &global_node_map,
			     std::vector<INT> &local_node_map)
{
  size_t offset = 0;
  size_t j = 0;
  size_t part_count = part_mesh.size();
  for (size_t p = 0; p < part_count; p++) {
    bool has_omissions = part_mesh[p]->get_property("block_omission_count").get_int() > 0;
    Ioss::NodeBlock *nb = part_mesh[p]->get_node_blocks()[0];
    size_t loc_size = nb->get_property("entity_count").get_int();
    if (has_omissions) {
      // If there are any omitted element blocks for this part, don't
      // map the nodes that are only connected to omitted element
      // blocks.
      std::vector<char> node_status;
      nb->get_field_data("node_connectivity_status", node_status);
      for (size_t i=0; i < node_status.size(); i++) {
	if (node_status[i] != 1) {
	  local_node_map[offset+i] = j;
	  global_node_map.push_back(j+1);
	  j++;
	} else {
	  local_node_map[offset+i] = -1;
	}
      }
    } else {
      for (size_t i=0; i < loc_size; i++) {
	local_node_map[offset+i] = j;
	global_node_map.push_back(j+1);
	j++;
      }
    }
    offset += loc_size;
  }
}
Пример #3
0
  void build_reverse_node_map(Ioss::Region &global,
			      RegionVector &part_mesh,
			      std::vector<INT> &global_node_map,
			      std::vector<INT> &local_node_map)
  {
    // Instead of using <set> and <map>, consider using a sorted vector...
    // Append all local node maps to the global node map.
    // Sort the global node map
    // Remove duplicates.
    // Position within map is now the map...
    // When building the local-part node to global id, use binary_search...

    size_t part_count = part_mesh.size();

    // Global node map and count.
    std::vector<std::vector<int> > global_nodes(part_count);

    size_t tot_size = 0;
    for (size_t p = 0; p < part_count; p++) {
      Ioss::NodeBlock *nb = part_mesh[p]->get_node_blocks()[0];
      size_t loc_size = nb->get_property("entity_count").get_int();
      tot_size += loc_size;
      global_nodes[p].resize(loc_size);
    }
    global_node_map.resize(tot_size);

    size_t offset = 0;
    bool any_omitted_nodes = false;
    for (size_t p = 0; p < part_count; p++) {
      Ioss::NodeBlock *nb = part_mesh[p]->get_node_blocks()[0];
      nb->get_field_data("ids", global_nodes[p]);

      // If there are any omitted element blocks for this part, set
      // the global id of any nodes that are only connected to omitted
      // element blocks to 0.
      bool has_omissions = part_mesh[p]->get_property("block_omission_count").get_int() > 0;
      if (has_omissions) {
	std::vector<char> node_status;
	nb->get_field_data("node_connectivity_status", node_status);
	for (size_t i=0; i < node_status.size(); i++) {
	  if (node_status[i] == 1) {
	    any_omitted_nodes = true;
	    global_nodes[p][i] = 0;
	  }
	}
      }

      std::copy(global_nodes[p].begin(), global_nodes[p].end(), &global_node_map[offset]);
      offset += global_nodes[p].size();
    }

    // Now, sort the global_node_map array and remove duplicates...
    uniqify(global_node_map);

    // If any omitted nodes, remove them from the global_node_map.
    // The id will be 0
    if (any_omitted_nodes) {
      typename std::vector<INT>::iterator pos = std::remove(global_node_map.begin(),
						   global_node_map.end(), 0);
      global_node_map.erase(pos, global_node_map.end());
    }

    size_t output_node_count = global_node_map.size();

    // See whether the node numbers are contiguous.  If so, we can map
    // the nodes back to their original location. Since the nodes are
    // sorted and there are no duplicates, we just need to see if the id
    // at global_node_map.size() == global_node_map.size();
    size_t max_id = global_node_map[output_node_count-1];

    bool is_contiguous = max_id == output_node_count;
    std::cerr  << "Node map " << (is_contiguous ? "is" : "is not") << " contiguous.\n";

    // Create the map that maps from a local part node to the
    // global map. This combines the mapping local part node to
    // 'global id' and then 'global id' to global position. The
    // mapping is now a direct lookup instead of a lookup followed by
    // a reverse map.
    typedef typename std::vector<INT>::iterator V_INT_iterator;
    V_INT_iterator cur_pos = global_node_map.begin();
    for (size_t p = 0; p < part_count; p++) {
      size_t noffset = part_mesh[p]->get_property("node_offset").get_int();
      size_t node_count = global_nodes[p].size();
      for (size_t i = 0; i < node_count; i++) {
	INT global_node = global_nodes[p][i];

	if (global_node > 0) {
	if (cur_pos == global_node_map.end() || *cur_pos != global_node) {
	  std::pair<V_INT_iterator, V_INT_iterator> iter = std::equal_range(global_node_map.begin(),
									    global_node_map.end(),
									    global_node);
	  if (iter.first == iter.second) {
	    INT n = global_node;
	    std::cerr << n << "\n";
	    SMART_ASSERT(iter.first != iter.second);
	  }
	  cur_pos = iter.first;
	}
	size_t nodal_value = cur_pos - global_node_map.begin();
	local_node_map[noffset+i] = nodal_value;
	++cur_pos;
	} else {
	  local_node_map[noffset+i] = -1;
	}
      }				
    }
    
    // Update the nodal ids to give a unique, non-repeating set.  If contiguous, then
    // there is nothing to do.  If not contiguous, then need to determine if there are any
    // repeats (id reuse) and if so, generate a new id for the repeated uses.
    if (!is_contiguous) {
      bool repeat_found = false;
      INT id_last = global_node_map[0];
      for (size_t i=1; i < output_node_count; i++) {
	if (global_node_map[i] == id_last) {
	  global_node_map[i] = ++max_id;
	  repeat_found = true;
	} else {
	  id_last = global_node_map[i];
	}
      }
      if (repeat_found) {
	std::cerr  << "Duplicate node ids were found. Their ids have been renumbered to remove duplicates.\n";
      }
    }
  }
Пример #4
0
void match_node_xyz(RegionVector &part_mesh,
		    double tolerance,
		    std::vector<INT> &global_node_map, std::vector<INT> &local_node_map)
{
  // See if any omitted element blocks...
  bool has_omissions = false;
  for (auto & elem : part_mesh) {
    if (elem->get_property("block_omission_count").get_int() > 0) {
      has_omissions = true;
      break;
    }
  }

  if (!has_omissions) {
    for (size_t i=0; i < local_node_map.size(); i++) {
      local_node_map[i] = i;
    }
  } else {
    std::vector<INT> dummy;
    eliminate_omitted_nodes(part_mesh, dummy, local_node_map);

    // The local_node_map is not quite in the correct format after the
    // call to 'eliminate_omitted_nodes'.  We need all non-omitted
    // nodes to have local_node_map[i] == i.
    for (size_t i=0; i < local_node_map.size(); i++) {
      if (local_node_map[i] >= 0) local_node_map[i] = i;
    }
  }
  
  size_t part_count = part_mesh.size();
  enum {X=0, Y=1, Z=2};

  for (size_t ip=0; ip < part_count; ip++) {
    vector3d i_max;
    vector3d i_min;
    std::vector<double> i_coord;
    Ioss::NodeBlock *inb = part_mesh[ip]->get_node_blocks()[0];
    inb->get_field_data("mesh_model_coordinates", i_coord);
    find_range(i_coord, i_min, i_max);
    
    size_t i_offset = part_mesh[ip]->get_property("node_offset").get_int();

    for (size_t jp=ip+1; jp < part_count; jp++) {
      vector3d j_max;
      vector3d j_min;
      std::vector<double> j_coord;
      Ioss::NodeBlock *jnb = part_mesh[jp]->get_node_blocks()[0];
      jnb->get_field_data("mesh_model_coordinates", j_coord);
      find_range(j_coord, j_min, j_max);

      size_t j_offset = part_mesh[jp]->get_property("node_offset").get_int();

      // See if the ranges overlap...
      vector3d max;
      vector3d min;
      max.x = std::min(i_max.x, j_max.x);
      max.y = std::min(i_max.y, j_max.y);
      max.z = std::min(i_max.z, j_max.z);

      min.x = std::max(i_min.x, j_min.x);
      min.y = std::max(i_min.y, j_min.y);
      min.z = std::max(i_min.z, j_min.z);

      double delta[3];
      int XYZ = X;
      delta[XYZ] = max.x - min.x;
      delta[Y] = max.y - min.y;
      if (delta[Y] > delta[XYZ])
	XYZ = Y;
      delta[Z] = max.z - min.z;
      if (delta[Z] > delta[XYZ])
	XYZ = Z;

      double epsilon = (delta[X] + delta[Y] + delta[Z]) / 1.0e3;
      if (epsilon < 0.0) {
	std::cout << "Parts " << ip << " and " << jp << " do not overlap.\n";
	continue;
      }

      min -= epsilon;
      max += epsilon;

      if (tolerance >= 0.0) epsilon = tolerance;

      std::vector<INT> j_inrange;
      std::vector<INT> i_inrange;

      find_in_range(j_coord, min, max, j_inrange);
      find_in_range(i_coord, min, max, i_inrange);

      // Index sort all nodes on the coordinate range with the maximum delta.
      index_coord_sort(i_coord, i_inrange, XYZ);
      index_coord_sort(j_coord, j_inrange, XYZ);

      if (i_inrange.size() < j_inrange.size()) {
	do_matching(i_inrange, i_coord, i_offset,
		    j_inrange, j_coord, j_offset,
		    epsilon, XYZ, local_node_map);
      } else {
	do_matching(j_inrange, j_coord, j_offset,
		    i_inrange, i_coord, i_offset,
		    epsilon, XYZ, local_node_map);
      }
    }
  }

  // Build the global and local maps...
  size_t j = 1;
  for (size_t i=0; i < local_node_map.size(); i++) {
    if (local_node_map[i] == (INT)i) {
      global_node_map.push_back(j);
      local_node_map[i] = j-1;
      j++;
    } else if (local_node_map[i] >= 0) {
      local_node_map[i] = local_node_map[local_node_map[i]];
    }
  }
}
Пример #5
0
  template <typename INT> void FaceGenerator::generate_faces(INT /*dummy*/)
  {
    Ioss::NodeBlock *nb = region_.get_node_blocks()[0];

    std::vector<INT> ids;
    nb->get_field_data("ids", ids);

    // Convert ids into hashed-ids
    auto                starth = std::chrono::high_resolution_clock::now();
    std::vector<size_t> hash_ids;
    hash_ids.reserve(ids.size());
    for (auto id : ids) {
      hash_ids.push_back(id_hash(id));
    }
    auto endh = std::chrono::high_resolution_clock::now();

    size_t numel = region_.get_property("element_count").get_int();

    faces_.reserve(3.3 * numel);

    Ioss::ElementBlockContainer ebs = region_.get_element_blocks();
    for (auto eb : ebs) {
      const Ioss::ElementTopology *topo = eb->topology();

      // Only handle continuum elements at this time...
      if (topo->parametric_dimension() != 3) {
        continue;
      }

      std::vector<INT> connectivity;
      eb->get_field_data("connectivity_raw", connectivity);

      std::vector<INT> elem_ids;
      eb->get_field_data("ids", elem_ids);

      int num_face_per_elem = topo->number_faces();
      assert(num_face_per_elem <= 6);
      std::array<Ioss::IntVector, 6> face_conn;
      std::array<int, 6>             face_count;
      for (int face = 0; face < num_face_per_elem; face++) {
        face_conn[face]  = topo->face_connectivity(face + 1);
        face_count[face] = topo->face_type(face + 1)->number_corner_nodes();
      }

      int    num_node_per_elem = topo->number_nodes();
      size_t num_elem          = eb->get_property("entity_count").get_int();

      for (size_t elem = 0, offset = 0; elem < num_elem; elem++, offset += num_node_per_elem) {
        for (int face = 0; face < num_face_per_elem; face++) {
          size_t id = 0;
          assert(face_count[face] <= 4);
          std::array<size_t, 4> conn = {{0, 0, 0, 0}};
          for (int j = 0; j < face_count[face]; j++) {
            size_t fnode = offset + face_conn[face][j];
            size_t gnode = connectivity[fnode];
            conn[j]      = ids[gnode - 1];
            id += hash_ids[gnode - 1];
          }
          create_face(faces_, id, conn, elem_ids[elem]);
        }
      }
    }

    auto endf = std::chrono::high_resolution_clock::now();
    resolve_parallel_faces(region_, faces_, hash_ids, (INT)0);
    auto endp = std::chrono::high_resolution_clock::now();

    auto diffh = endh - starth;
    auto difff = endf - endh;
    auto diffp = endp - endf;

    std::cout << "Node ID hash time:   \t"
              << std::chrono::duration<double, std::milli>(diffh).count() << " ms\t"
              << hash_ids.size() / std::chrono::duration<double>(diffh).count()
              << " nodes/second\n";
    std::cout << "Face generation time:\t"
              << std::chrono::duration<double, std::milli>(difff).count() << " ms\t"
              << faces_.size() / std::chrono::duration<double>(difff).count() << " faces/second.\n";
#ifdef HAVE_MPI
    size_t proc_count = region_.get_database()->util().parallel_size();

    if (proc_count > 1) {
      std::cout << "Parallel time:       \t"
                << std::chrono::duration<double, std::milli>(diffp).count() << " ms\t"
                << faces_.size() / std::chrono::duration<double>(diffp).count()
                << " faces/second.\n";
    }
#endif
    std::cout << "Total time:          \t"
              << std::chrono::duration<double, std::milli>(endp - starth).count() << " ms\n\n";
  }