Example #1
0
void exchanger_verify(exchanger_t* ex, void (*handler)(const char* format, ...))
{
#if POLYMEC_HAVE_MPI
  START_FUNCTION_TIMER();
  // An exchanger is valid/consistent iff the number of elements that 
  // are exchanged between any two processors are agreed upon between those 
  // two processors. So we send our expected number of exchanged elements 
  // to our neighbors, and receive their numbers, and then compare.
  int num_send_procs = ex->send_map->size;
  int num_receive_procs = ex->receive_map->size;
  int num_sent_elements[num_send_procs], 
      num_elements_expected_by_neighbors[num_send_procs],
      send_procs[num_send_procs];
  MPI_Request requests[num_send_procs + num_receive_procs];
  int pos = 0, proc, *indices, num_indices;

  // Post receives for numbers of elements we send to others.
  int p = 0;
  while (exchanger_next_send(ex, &pos, &proc, &indices, &num_indices))
  {
    num_sent_elements[p] = num_indices;
    send_procs[p] = proc;
    int err = MPI_Irecv(&num_elements_expected_by_neighbors[p], 1, 
                        MPI_INT, proc, 0, ex->comm, &requests[p]);
    if (err != MPI_SUCCESS)
      polymec_error("exchanger_verify: Could not receive sent element data from %d", proc);
    ++p;
  }

  // Send our receive neighbors the number that we expect to receive. This 
  // means that we will get the number that our neighbors expect to receive,
  // which should be the same number as what we're sending.
  pos = p = 0;
  while (exchanger_next_receive(ex, &pos, &proc, &indices, &num_indices))
  {
    int err = MPI_Isend(&num_indices, 1, MPI_INT, proc, 0, ex->comm, &requests[num_send_procs + p]);
    if (err != MPI_SUCCESS)
      polymec_error("exchanger_verify: Could not send number of received elements to %d", proc);
    ++p;
  }

  // Wait for messages to fly.
  MPI_Status statuses[num_send_procs + num_receive_procs];
  MPI_Waitall(num_send_procs + num_receive_procs, requests, statuses);

  // Now verify that the numbers are the same.
  for (p = 0; p < num_send_procs; ++p)
  {
    if (num_sent_elements[p] != num_elements_expected_by_neighbors[p])
    {
      handler("exchanger_verify: Sending %d elements to proc %d, but %d elements are expected.", 
              num_sent_elements[p], send_procs[p],
              num_elements_expected_by_neighbors[p]);
    }
  }
  STOP_FUNCTION_TIMER();
#endif
}
Example #2
0
void use_units_system(int units_system_name)
{
  if (units_systems == NULL)
    polymec_error("use_units_system: No valid units system is defined!");
  int_real_unordered_map_t** ptr = (int_real_unordered_map_t**)int_ptr_unordered_map_get(units_systems, units_system_name);
  if (ptr == NULL)
    polymec_error("use_units_system: units system %d is not defined!", units_system_name);
  current_units = *ptr;
}
Example #3
0
void set_physical_constant(int physical_constant_name, real_t value, int units_system_name)
{
  if (units_systems == NULL)
    polymec_error("set_physical_constant: No valid units system is defined!");
  int_real_unordered_map_t** ptr = (int_real_unordered_map_t**)int_ptr_unordered_map_get(units_systems, units_system_name);
  if (ptr == NULL)
    polymec_error("set_physical_constant: units system %d is not defined!", units_system_name);
  int_real_unordered_map_t* units = *ptr;
  int_real_unordered_map_insert(units, physical_constant_name, value);
}
Example #4
0
static size_t mpi_size(MPI_Datatype type)
{
  size_t size = 0;
  if (type == MPI_REAL_T)
    size = sizeof(real_t);
  else if (type == MPI_DOUBLE)
    size = sizeof(double);
  else if (type == MPI_FLOAT)
    size = sizeof(float);
  else if (type == MPI_INT)
    size = sizeof(int);
  else if (type == MPI_LONG)
    size = sizeof(long);
  else if (type == MPI_LONG_LONG)
    size = sizeof(long long);
  else if (type == MPI_UINT64_T)
    size = sizeof(uint64_t);
  else if (type == MPI_CHAR)
    size = sizeof(char);
  else if (type == MPI_BYTE)
    size = sizeof(uint8_t);
  else 
    polymec_error("Unsupported MPI data type used.");
  return size;
}
Example #5
0
exodus_file_t* exodus_file_open(MPI_Comm comm,
                                const char* filename)
{
  if (!file_exists(filename))
    polymec_error("exodus_file_open: %s does not exist.", filename);
  return open_exodus_file(comm, filename, EX_READ);
}
Example #6
0
void define_units_system(int units_system_name)
{
  if (units_systems == NULL)
    units_systems = int_ptr_unordered_map_new();
  if (int_ptr_unordered_map_contains(units_systems, units_system_name))
    polymec_error("define_units_system: units system %d is already defined.", units_system_name);
  int_ptr_unordered_map_insert_with_v_dtor(units_systems, 
                                           units_system_name, 
                                           int_real_unordered_map_new(),
                                           DTOR(int_real_unordered_map_free));
}
Example #7
0
void amr_grid_finalize(amr_grid_t* grid)
{
  ASSERT(!grid->finalized);

  // Make sure that we have accounted for all patches in our construction 
  // process.
  DECLARE_3D_ARRAY(patch_type_t, patch_types, grid->patch_types, grid->nx, grid->ny, grid->nz);
  if (grid->num_local_patches < (grid->nx * grid->ny * grid->nz))
  {
    for (int i = 0; i < grid->nx; ++i)
    {
      for (int j = 0; j < grid->ny; ++j)
      {
        for (int k = 0; k < grid->nz; ++k)
        {
          if (patch_types[i][j][k] == NO_PATCH)
            polymec_error("amr_grid_finalize: no local or remote patch at (%d, %d, %d).", i, j, k);
        }
      }
    }
  }

  // Make an array of indices for locally-present patches.
  grid->local_patch_indices = polymec_malloc(sizeof(int) * 3 * grid->num_local_patches);
  int l = 0;
  for (int i = 0; i < grid->nx; ++i)
  {
    for (int j = 0; j < grid->ny; ++j)
    {
      for (int k = 0; k < grid->nz; ++k, ++l)
      {
        grid->local_patch_indices[3*l]   = i;
        grid->local_patch_indices[3*l+1] = j;
        grid->local_patch_indices[3*l+2] = k;
      }
    }
  }

  // Establish our remote copying pattern.
  grid->cell_ex = grid_cell_exchanger_new(grid);
  grid->x_face_ex = grid_x_face_exchanger_new(grid);
  grid->y_face_ex = grid_y_face_exchanger_new(grid);
  grid->z_face_ex = grid_z_face_exchanger_new(grid);
  grid->x_edge_ex = grid_x_edge_exchanger_new(grid);
  grid->y_edge_ex = grid_y_edge_exchanger_new(grid);
  grid->z_edge_ex = grid_z_edge_exchanger_new(grid);
  grid->node_ex = grid_node_exchanger_new(grid);
  grid->finalized = true;
}
Example #8
0
polygon2_t* polygon2_star(point2_t* x0, point2_t* points, int num_points)
{
  // Make sure x0 is not one of the points.
  for (int i = 0; i < num_points; ++i)
  {
    if (point2_distance(x0, &points[i]) < 1e-14)
      polymec_error("polygon2_star: Point %d coincides with x0.", i);
  }

  // Sort the points by angles.
  star_angle_t angles[num_points];
  for (int i = 0; i < num_points; ++i)
  {
    angles[i].angle = atan2(points[i].y - x0->y, points[i].x - x0->x);
    angles[i].index = i;
  }
  qsort(angles, (size_t)num_points, sizeof(star_angle_t), star_angle_cmp);
  
  // Create a polygon from the new ordering.
  int ordering[num_points];
  for (int i = 0; i < num_points; ++i)
    ordering[i] = angles[i].index;
  return polygon2_new_with_ordering(points, ordering, num_points);
}
mesh_t* create_uniform_mesh_on_rank(MPI_Comm comm, int rank,
                                    int nx, int ny, int nz, bbox_t* bbox)
{
  ASSERT(comm != MPI_COMM_SELF);
  ASSERT(rank >= 0);

  int my_rank, nprocs;
  MPI_Comm_rank(comm, &my_rank);
  MPI_Comm_rank(comm, &nprocs);

  if (rank > nprocs)
    polymec_error("create_uniform_mesh_on_rank: invalid rank: %d", rank);

  mesh_t* mesh = NULL;
  if (my_rank == rank)
    mesh = create_uniform_mesh(comm, nx, ny, nz, bbox);
  else
  {
    // Initialize serializers.
    serializer_t* s = cubic_lattice_serializer();
    s = bbox_serializer();
  }
  return mesh;
}
Example #10
0
// This helper sets up the exchanger ex so that it can migrate data from the 
// current process according to the local partition vector.
exchanger_t* create_migrator(MPI_Comm comm,
                             int64_t* local_partition,
                             int num_vertices)
{
  START_FUNCTION_TIMER();
  exchanger_t* migrator = exchanger_new(comm);
  
  // Tally up the number of vertices we're going to send to every other process, 
  // including those that are staying on our own.
  int nprocs, rank;
  MPI_Comm_size(comm, &nprocs);
  MPI_Comm_rank(comm, &rank);
  int num_vertices_to_send[nprocs];
  memset(num_vertices_to_send, 0, sizeof(int) * nprocs);
  for (int v = 0; v < num_vertices; ++v)
    num_vertices_to_send[local_partition[v]]++;

  // Get the number of vertices we're going to receive from every other process.
  int num_vertices_to_receive[nprocs];
  MPI_Alltoall(num_vertices_to_send, 1, MPI_INT, 
               num_vertices_to_receive, 1, MPI_INT, comm);

  // Send and receive the actual vertices.
  int** receive_vertices = polymec_malloc(sizeof(int*) * nprocs);
  memset(receive_vertices, 0, sizeof(int*) * nprocs);
  int num_requests = 0;
  for (int p = 0; p < nprocs; ++p)
  {
    if ((rank != p) && (num_vertices_to_receive[p] > 0)) ++num_requests;
    if ((rank != p) && (num_vertices_to_send[p] > 0)) ++num_requests;
  }
  if (num_requests > 0)
  {
    MPI_Request requests[num_requests];
    int r = 0;
    for (int p = 0; p < nprocs; ++p)
    {
      if (num_vertices_to_receive[p] > 0)
      {
        receive_vertices[p] = polymec_malloc(sizeof(int) * num_vertices_to_receive[p]);
        if (p != rank)
        {
          // Note that we use this rank as our tag.
          MPI_Irecv(receive_vertices[p], num_vertices_to_receive[p], MPI_INT, p, rank, comm, &requests[r++]);
        }
      }
      if (num_vertices_to_send[p] > 0)
      {
        int send_vertices[num_vertices_to_send[p]], s = 0;
        for (int v = 0; v < num_vertices; ++v)
        {
          if (local_partition[v] == p)
            send_vertices[s++] = v;
        }
        if (p != rank)
        {
          // Note that we use the destination rank p as our tag.
          exchanger_set_send(migrator, p, send_vertices, num_vertices_to_send[p], true);
          MPI_Isend(send_vertices, num_vertices_to_send[p], MPI_INT, p, p, comm, &requests[r++]);
        }
        else
          memcpy(receive_vertices[rank], send_vertices, sizeof(int) * num_vertices_to_receive[rank]);
      }
    }
    ASSERT(r == num_requests);

    // Wait for exchanges to finish. We can't use MPI_Waitall here because 
    // not all processes necessary participate.
    MPI_Status statuses[num_requests];
    int finished[num_requests];
    memset(finished, 0, num_requests*sizeof(int));
    while (true)
    {
      bool all_finished = true;
      for (int i = 0; i < num_requests; ++i)
      {
        if (!finished[i])
        {
          if (MPI_Test(&requests[i], &finished[i], &statuses[i]) != MPI_SUCCESS)
            polymec_error("create_migrator: Internal error.");
          if (!finished[i]) all_finished = false;
        }
      }

      // If the transmissions have finished at this point, we 
      // can break out of the loop. 
      if (all_finished) break;
    } 

    // Now register all the vertices we're receiving with the migrator.
    for (int p = 0; p < nprocs; ++p)
    {
      if (num_vertices_to_receive[p] > 0)
      {
        ASSERT(receive_vertices[p] != NULL);
        if (rank != p)
          exchanger_set_receive(migrator, p, receive_vertices[p], num_vertices_to_receive[p], true);
        polymec_free(receive_vertices[p]);
      }
    }
    polymec_free(receive_vertices);
  }

  STOP_FUNCTION_TIMER();
  return migrator;
}
Example #11
0
void exchanger_finish_transfer(exchanger_t* ex, int token)
{
#if POLYMEC_HAVE_MPI
  START_FUNCTION_TIMER();
  ASSERT(token >= 0);
  ASSERT(token < ex->num_pending_msgs);
  ASSERT(ex->transfer_counts[token] != NULL); // We can't finish an exchange as a transfer!

  // Retrieve the message for the given token.
  mpi_message_t* msg = ex->pending_msgs[token];
  int* count = ex->transfer_counts[token];
  int err = exchanger_waitall(ex, msg);
  if (err != MPI_SUCCESS) return;

  // Copy the received data into the original array.
  void* orig_buffer = ex->orig_buffers[token];
  mpi_message_unpack(msg, orig_buffer, ex->receive_offset, ex->receive_map);

  // Now cull the sent elements from the array.
  int num_sent = 0, pos = 0, proc;
  exchanger_channel_t* c;
  while (exchanger_map_next(ex->send_map, &pos, &proc, &c))
  {
    // Move the sent elements to the back.
    int stride = msg->stride;
    if (msg->type == MPI_REAL_T)
    {
      real_t* array = (real_t*)orig_buffer;
      for (int i = 0; i < c->num_indices; ++i)
      {
        for (int s = 0; s < stride; ++s)
        {
          array[stride*c->indices[i]+s] = array[*count-1-num_sent];
          ++num_sent;
        }
      }
    }
    else if (msg->type == MPI_DOUBLE)
    {
      double* array = (double*)orig_buffer;
      for (int i = 0; i < c->num_indices; ++i)
      {
        for (int s = 0; s < stride; ++s)
        {
          array[stride*c->indices[i]+s] = array[*count-1-num_sent];
          ++num_sent;
        }
      }
    }
    else 
    {
      // FIXME: What about other data types???
      polymec_error("exchanger_finish_transfer: unimplemented data type.");
    }
  }

  // Convey the change in count of the transferred data.
  *count -= num_sent;
  ASSERT(*count >= 0);

  // Pull the message out of our list of pending messages and delete it.
  ex->pending_msgs[token] = NULL;
  ex->orig_buffers[token] = NULL;
  ex->transfer_counts[token] = NULL;
  mpi_message_free(msg);
  STOP_FUNCTION_TIMER();
#endif
}
Example #12
0
void exodus_file_write_mesh(exodus_file_t* file,
                            fe_mesh_t* mesh)
{
  ASSERT(file->writing);

  // See whether we have polyhedral blocks, and whether the non-polyhedral
  // blocks have supported element types.
  int num_blocks = fe_mesh_num_blocks(mesh);
  bool is_polyhedral = false;
  int pos = 0;
  char* block_name;
  fe_block_t* block;
  while (fe_mesh_next_block(mesh, &pos, &block_name, &block))
  {
    fe_mesh_element_t elem_type = fe_block_element_type(block);
    if (elem_type == FE_POLYHEDRON)
    {
      is_polyhedral = true;
      break;
    }
    else if (elem_type != FE_INVALID)
    {
      // Check the number of nodes for the element.
      if (!element_is_supported(elem_type, fe_block_num_element_nodes(block, 0)))
        polymec_error("exodus_file_write_mesh: Element type in block %s has invalid number of nodes.", block_name);
    }
    else
      polymec_error("exodus_file_write_mesh: Invalid element type for block %s.", block_name);
  }

  // Write out information about elements, faces, edges, nodes.
  file->num_nodes = fe_mesh_num_nodes(mesh);
  ex_init_params params;
  strcpy(params.title, file->title);
  params.num_dim = 3;
  params.num_nodes = file->num_nodes;
  int num_edges = fe_mesh_num_edges(mesh);
  params.num_edge = num_edges;
  params.num_edge_blk = 0;
  int num_faces = fe_mesh_num_faces(mesh);
  params.num_face = num_faces;
  params.num_face_blk = (is_polyhedral) ? 1 : 0;
  int num_elem = fe_mesh_num_elements(mesh);
  params.num_elem = num_elem;
  params.num_elem_blk = num_blocks;
  params.num_elem_sets = file->num_elem_sets = fe_mesh_num_element_sets(mesh);
  params.num_face_sets = file->num_face_sets = fe_mesh_num_face_sets(mesh);
  params.num_edge_sets = file->num_edge_sets = fe_mesh_num_edge_sets(mesh);
  params.num_node_sets = file->num_node_sets = fe_mesh_num_node_sets(mesh);
  params.num_side_sets = file->num_side_sets = fe_mesh_num_side_sets(mesh);
  params.num_elem_maps = 0;
  params.num_face_maps = 0;
  params.num_edge_maps = 0;
  params.num_node_maps = 0;
  ex_put_init_ext(file->ex_id, &params);

  // If we have any polyhedral element blocks, we write out a single face 
  // block that incorporates all of the polyhedral elements.
  if (is_polyhedral)
  {
    // Generate face->node connectivity information.
    int num_pfaces = fe_mesh_num_faces(mesh);
    int face_node_size = 0;
    int num_face_nodes[num_pfaces];
    for (int f = 0; f < num_pfaces; ++f)
    {
      int num_nodes = fe_mesh_num_face_nodes(mesh, f);
      num_face_nodes[f] = num_nodes;
      face_node_size += num_nodes;
    }
    int* face_nodes = polymec_malloc(sizeof(int) * face_node_size);
    int offset = 0;
    for (int f = 0; f < num_pfaces; ++f)
    {
      fe_mesh_get_face_nodes(mesh, f, &face_nodes[offset]);
      offset += num_face_nodes[f];
    }
    for (int i = 0; i < face_node_size; ++i)
      face_nodes[i] += 1;

    // Write an "nsided" face block.
    ex_put_block(file->ex_id, EX_FACE_BLOCK, 1, "nsided",
                 num_pfaces, face_node_size, 0, 0, 0);
    ex_put_name(file->ex_id, EX_FACE_BLOCK, 1, "face_block");
    ex_put_conn(file->ex_id, EX_FACE_BLOCK, 1, face_nodes, NULL, NULL);

    // Clean up.
    polymec_free(face_nodes);

    // Number of nodes per face.
    ex_put_entity_count_per_polyhedra(file->ex_id, EX_FACE_BLOCK, 
                                      1, num_face_nodes); 
  }

  // Go over the element blocks and write out the data.
  pos = 0;
  while (fe_mesh_next_block(mesh, &pos, &block_name, &block))
  {
    int elem_block = pos;
    int num_e = fe_block_num_elements(block);
    fe_mesh_element_t elem_type = fe_block_element_type(block);
    if (elem_type == FE_POLYHEDRON)
    {
      // Count up the faces in the block and write the block information.
      int tot_num_elem_faces = 0;
      int faces_per_elem[num_e];
      for (int i = 0; i < num_e; ++i)
      {
        faces_per_elem[i] = fe_block_num_element_faces(block, i);
        tot_num_elem_faces += faces_per_elem[i];
      }
      ex_put_block(file->ex_id, EX_ELEM_BLOCK, elem_block, "nfaced", 
                   num_e, 0, 0, tot_num_elem_faces, 0);

      // Write elem->face connectivity information.
      int elem_faces[tot_num_elem_faces], offset = 0;
      for (int i = 0; i < num_e; ++i)
      {
        fe_block_get_element_faces(block, i, &elem_faces[offset]);
        offset += faces_per_elem[i];
      }
      for (int i = 0; i < tot_num_elem_faces; ++i)
        elem_faces[i] += 1;
      ex_put_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, NULL, NULL, elem_faces);
      ex_put_entity_count_per_polyhedra(file->ex_id, EX_ELEM_BLOCK, elem_block, faces_per_elem); 
    }
    else if (elem_type != FE_INVALID)
    {
      // Get element information.
      char elem_type_name[MAX_NAME_LENGTH+1];
      get_elem_name(elem_type, elem_type_name);
      int num_nodes_per_elem = fe_block_num_element_nodes(block, 0);

      // Write the block.
      ex_put_block(file->ex_id, EX_ELEM_BLOCK, elem_block, elem_type_name, 
                   num_e, num_nodes_per_elem, 0, 0, 0);

      // Write the elem->node connectivity.
      int elem_nodes[num_e* num_nodes_per_elem], offset = 0;
      for (int i = 0; i < num_e; ++i)
      {
        fe_block_get_element_nodes(block, i, &elem_nodes[offset]);
        offset += num_nodes_per_elem;
      }
      for (int i = 0; i < num_e* num_nodes_per_elem; ++i)
        elem_nodes[i] += 1;
      ex_put_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, elem_nodes, NULL, NULL);
    }

    // Set the element block name.
    ex_put_name(file->ex_id, EX_ELEM_BLOCK, elem_block, block_name);
  }

  // Set node positions.
  real_t x[file->num_nodes], y[file->num_nodes], z[file->num_nodes];
  point_t* X = fe_mesh_node_positions(mesh);
  for (int n = 0; n < file->num_nodes; ++n)
  {
    x[n] = X[n].x;
    y[n] = X[n].y;
    z[n] = X[n].z;
  }
  ex_put_coord(file->ex_id, x, y, z);
  char* coord_names[3] = {"x", "y", "z"};
  ex_put_coord_names(file->ex_id, coord_names);

  // Write sets of entities.
  int *set, set_id = 0;
  size_t set_size;
  char* set_name;
  pos = set_id = 0;
  while (fe_mesh_next_element_set(mesh, &pos, &set_name, &set, &set_size))
    write_set(file, EX_ELEM_SET, ++set_id, set_name, set, set_size);
  pos = set_id = 0;
  while (fe_mesh_next_face_set(mesh, &pos, &set_name, &set, &set_size))
    write_set(file, EX_FACE_SET, ++set_id, set_name, set, set_size);
  pos = set_id = 0;
  while (fe_mesh_next_edge_set(mesh, &pos, &set_name, &set, &set_size))
    write_set(file, EX_EDGE_SET, ++set_id, set_name, set, set_size);
  pos = set_id = 0;
  while (fe_mesh_next_node_set(mesh, &pos, &set_name, &set, &set_size))
    write_set(file, EX_NODE_SET, ++set_id, set_name, set, set_size);
  pos = set_id = 0;
  while (fe_mesh_next_side_set(mesh, &pos, &set_name, &set, &set_size))
    write_set(file, EX_SIDE_SET, ++set_id, set_name, set, set_size);
}
void create_boundary_generators(ptr_array_t* surface_points, 
                                ptr_array_t* surface_normals, 
                                ptr_array_t* surface_tags,
                                point_t** boundary_generators,
                                int* num_boundary_generators,
                                char*** tag_names,
                                int_array_t*** tags,
                                int* num_tags)
{
  ASSERT(surface_points->size >= 4); // surface must be closed!
  ASSERT(surface_points->size == surface_normals->size);
  ASSERT(surface_points->size == surface_tags->size);

  int num_surface_points = surface_points->size;

  // Compute the minimum distance from each surface point to its neighbors.
  real_t* h_min = polymec_malloc(sizeof(real_t) * num_surface_points);
  {
    // Dump the surface points into a kd-tree.
    point_t* surf_points = polymec_malloc(sizeof(point_t) * num_surface_points);
    for (int i = 0; i < num_surface_points; ++i)
      surf_points[i] = *((point_t*)surface_points->data[i]);
    kd_tree_t* tree = kd_tree_new(surf_points, num_surface_points);

    int neighbors[2];
    for (int i = 0; i < num_surface_points; ++i)
    {
      // Find the "nearest 2" points to the ith surface point--the first is 
      // the point itself, and the second is its nearest neighbor.
      // FIXME: Serious memory error within here. We work around it for 
      // FIXME: the moment by freshing the tree pointer, which is 
      // FIXME: corrupted. ICK!
      kd_tree_t* tree_p = tree;
      kd_tree_nearest_n(tree, &surf_points[i], 2, neighbors);
      tree = tree_p;
      ASSERT(neighbors[0] == i);
      ASSERT(neighbors[1] >= 0);
      ASSERT(neighbors[1] < num_surface_points);
      h_min[i] = point_distance(&surf_points[i], &surf_points[neighbors[1]]);
    }

    // Clean up.
    kd_tree_free(tree);
    polymec_free(surf_points);
  }

  // Generate boundary points for each surface point based on how many 
  // surfaces it belongs to. 
  ptr_array_t* boundary_points = ptr_array_new();
  string_int_unordered_map_t* tag_indices = string_int_unordered_map_new();
  ptr_array_t* boundary_tags = ptr_array_new();
  for (int i = 0; i < num_surface_points; ++i)
  {
    // Add any tags from this point to the set of existing boundary tags.
    string_slist_t* tags = surface_tags->data[i];
    for (string_slist_node_t* t_iter = tags->front; t_iter != NULL; t_iter = t_iter->next)
      string_int_unordered_map_insert(tag_indices, t_iter->value, tag_indices->size);

    // Retrieve the surface point.
    point_t* x_surf = surface_points->data[i];

    // Retrieve the list of normal vectors for this surface point.
    ptr_slist_t* normal_list = surface_normals->data[i];
    int num_normals = normal_list->size;
    vector_t normals[num_normals];
    int n_offset = 0;
    for (ptr_slist_node_t* n_iter = normal_list->front; n_iter != NULL; n_iter = n_iter->next)
      normals[n_offset++] = *((vector_t*)n_iter->value);

    // For now, let's keep things relatively simple.
    if (num_normals > 2)
    {
      polymec_error("create_boundary_generators: Too many normal vectors (%d) for surface point %d at (%g, %g, %g)",
                    num_normals, i, x_surf->x, x_surf->y, x_surf->z);
    }

    // Create boundary points based on this list of normals.
    if (num_normals == 1)
    {
      // This point only belongs to one surface, so we create boundary points 
      // on either side of it.
      point_t* x_out = polymec_malloc(sizeof(point_t));
      x_out->x = x_surf->x + h_min[i]*normals[0].x;
      x_out->y = x_surf->y + h_min[i]*normals[0].y;
      x_out->z = x_surf->z + h_min[i]*normals[0].z;
      ptr_array_append_with_dtor(boundary_points, x_out, polymec_free);

      point_t* x_in = polymec_malloc(sizeof(point_t));
      x_in->x = x_surf->x - h_min[i]*normals[0].x;
      x_in->y = x_surf->y - h_min[i]*normals[0].y;
      x_in->z = x_surf->z - h_min[i]*normals[0].z;
      ptr_array_append_with_dtor(boundary_points, x_in, polymec_free);
    }
    else if (num_normals == 2)
    {
      // This point appears at the interface between two surfaces.
      // (Or so it seems.)
      ASSERT(vector_dot(&normals[0], &normals[1]) < 0.0);

      point_t* x1 = polymec_malloc(sizeof(point_t));
      x1->x = x_surf->x + h_min[i]*normals[0].x;
      x1->y = x_surf->y + h_min[i]*normals[0].y;
      x1->z = x_surf->z + h_min[i]*normals[0].z;
      ptr_array_append_with_dtor(boundary_points, x1, polymec_free);

      point_t* x2 = polymec_malloc(sizeof(point_t));
      x2->x = x_surf->x - h_min[i]*normals[1].x;
      x2->y = x_surf->y - h_min[i]*normals[1].y;
      x2->z = x_surf->z - h_min[i]*normals[1].z;
      ptr_array_append_with_dtor(boundary_points, x2, polymec_free);
    }

    // Tag the boundary point appropriately.
    ptr_array_append(boundary_tags, tags); // Borrowed ref to tags.
  }

  // Move the surface points into a contiguous array.
  *boundary_generators = polymec_malloc(sizeof(point_t) * boundary_points->size);
  *num_boundary_generators = boundary_points->size;
  for (int i = 0; i < boundary_points->size; ++i)
  {
    (*boundary_generators)[i] = *((point_t*)boundary_points->data[i]);
  }

  // Transcribe the tags.
  *tag_names = polymec_malloc(sizeof(char*) * tag_indices->size);
  *tags = polymec_malloc(sizeof(int_array_t*) * tag_indices->size);
  *num_tags = tag_indices->size;
  char* tag_name;
  int pos = 0, tag_index;
  while (string_int_unordered_map_next(tag_indices, &pos, &tag_name, &tag_index))
  {
    (*tag_names)[tag_index] = string_dup(tag_name);
    (*tags)[tag_index] = int_array_new();
    for (int j = 0; j < *num_boundary_generators; ++j)
      int_array_append((*tags)[tag_index], tag_index);
  }

  // Clean up.
  string_int_unordered_map_free(tag_indices);
  polymec_free(h_min);
}
Example #14
0
// Copies data from the patch buffer to the patches in the given grid.
static void patch_buffer_copy_out(patch_buffer_t* buffer, amr_grid_data_t* grid_data)
{
  amr_grid_t* grid = amr_grid_data_grid(grid_data);
  amr_grid_data_centering_t centering = amr_grid_data_centering(grid_data);
  int num_components = amr_grid_data_num_components(grid_data);
  int num_ghosts = amr_grid_data_num_ghosts(grid_data);

  // Now count up the sent data for each patch.
  int local_mask = LOCAL_SAME_LEVEL | LOCAL_FINER_LEVEL | LOCAL_COARSER_LEVEL;
  int pos = 0, i, j, k, p = 0;
  amr_patch_t* patch;
  DECLARE_3D_ARRAY(patch_type_t, patch_types, grid->patch_types, grid->nx, grid->ny, grid->nz);
  while (amr_grid_data_next_local_patch(grid_data, &pos, &i, &j, &k, &patch))
  {
    patch_type_t patch_type = patch_types[i][j][k];
    if (patch_type == LOCAL_SAME_LEVEL)
      polymec_error("patch_buffer_copy_out: adaptive mesh refinement is not yet supported!");

    DECLARE_AMR_PATCH_ARRAY(array, patch);
    int offset = buffer->patch_receive_offsets[p];

    // Copy out -x values.
    int num_values = num_transmitted_patch_values(grid, centering, local_mask, i, j, k, i-1, j, k);
    for (int j = patch->j1; j < patch->j2; ++j)
      for (int k = patch->k1; k < patch->k2; ++k)
        for (int g = 0; g < num_ghosts; ++g)
          for (int c = 0; c < num_components; ++c, ++offset)
            array[g][j][k][c] = buffer->data[offset];

    // Copy out +x values.
    num_values = num_transmitted_patch_values(grid, centering, local_mask, i, j, k, i+1, j, k);
    for (int j = patch->j1; j < patch->j2; ++j)
      for (int k = patch->k1; k < patch->k2; ++k)
        for (int g = 0; g < num_ghosts; ++g)
          for (int c = 0; c < num_components; ++c, ++offset)
            array[patch->i2+num_ghosts-g-1][j][k][c] = buffer->data[offset];

    // Copy out -y values.
    num_values = num_transmitted_patch_values(grid, centering, local_mask, i, j, k, i, j-1, k);
    for (int i = patch->i1; i < patch->i2; ++i)
      for (int k = patch->k1; k < patch->k2; ++k)
        for (int g = 0; g < num_ghosts; ++g)
          for (int c = 0; c < num_components; ++c, ++offset)
            array[i][g][k][c] = buffer->data[offset];

    // Copy out +y values.
    num_values = num_transmitted_patch_values(grid, centering, local_mask, i, j, k, i, j+1, k);
    for (int i = patch->i1; i < patch->i2; ++i)
      for (int k = patch->k1; k < patch->k2; ++k)
        for (int g = 0; g < num_ghosts; ++g)
          for (int c = 0; c < num_components; ++c, ++offset)
            array[i][patch->j2+num_ghosts-g-1][k][c] = buffer->data[offset];

    // Copy out -z values.
    num_values = num_transmitted_patch_values(grid, centering, local_mask, i, j, k, i, j, k-1);
    for (int i = patch->i1; i < patch->i2; ++i)
      for (int j = patch->j1; j < patch->j2; ++j)
        for (int g = 0; g < num_ghosts; ++g)
          for (int c = 0; c < num_components; ++c, ++offset)
            array[i][j][g][c] = buffer->data[offset];

    // Copy out +z values.
    num_values = num_transmitted_patch_values(grid, centering, local_mask, i, j, k, i, j, k+1);
    for (int i = patch->i1; i < patch->i2; ++i)
      for (int j = patch->j1; j < patch->j2; ++j)
        for (int g = 0; g < num_ghosts; ++g)
          for (int c = 0; c < num_components; ++c, ++offset)
            array[i][j][patch->k2+num_ghosts-g-1][c] = buffer->data[offset];

    ASSERT(offset == buffer->patch_receive_offsets[p+1]);
    ++p;
  }
}
Example #15
0
fe_mesh_t* exodus_file_read_mesh(exodus_file_t* file)
{
  // Create the "host" FE mesh.
  fe_mesh_t* mesh = fe_mesh_new(file->comm, file->num_nodes);

  // Count up the number of polyhedral blocks.
  int num_poly_blocks = 0;
  for (int i = 0; i < file->num_elem_blocks; ++i)
  {
    int elem_block = file->elem_block_ids[i];
    char elem_type_name[MAX_NAME_LENGTH+1];
    int num_elem, num_nodes_per_elem, num_faces_per_elem;
    ex_get_block(file->ex_id, EX_ELEM_BLOCK, elem_block, 
                 elem_type_name, &num_elem,
                 &num_nodes_per_elem, NULL,
                 &num_faces_per_elem, NULL);
    fe_mesh_element_t elem_type = get_element_type(elem_type_name);
    if (elem_type == FE_POLYHEDRON)
      ++num_poly_blocks;
  }

  // If we have any polyhedral element blocks, we read a single face 
  // block that incorporates all of the polyhedral elements.
  if (num_poly_blocks > 0)
  {
    // Dig up the face block corresponding to this element block.
    char face_type[MAX_NAME_LENGTH+1];
    int num_faces, num_nodes;
    ex_get_block(file->ex_id, EX_FACE_BLOCK, file->face_block_ids[0], face_type, &num_faces,
                 &num_nodes, NULL, NULL, NULL);
    if (string_ncasecmp(face_type, "nsided", 6) != 0)
    {
      fe_mesh_free(mesh);
      ex_close(file->ex_id);
      polymec_error("Invalid face type for polyhedral element block.");
    }

    // Find the number of nodes for each face in the block.
    int* num_face_nodes = polymec_malloc(sizeof(int) * num_faces);
    ex_get_entity_count_per_polyhedra(file->ex_id, EX_FACE_BLOCK, 
                                      file->face_block_ids[0], 
                                      num_face_nodes);

    // Read face->node connectivity information.
    int face_node_size = 0;
    for (int i = 0; i < num_faces; ++i)
      face_node_size += num_face_nodes[i];
    int* face_nodes = polymec_malloc(sizeof(int) * face_node_size);
    ex_get_conn(file->ex_id, EX_FACE_BLOCK, 1, face_nodes, NULL, NULL);
    for (int i = 0; i < face_node_size; ++i)
      face_nodes[i] -= 1;
    fe_mesh_set_face_nodes(mesh, num_faces, num_face_nodes, face_nodes);

    // Clean up.
    polymec_free(num_face_nodes);
  }

  // Go over the element blocks and feel out the data.
  for (int i = 0; i < file->num_elem_blocks; ++i)
  {
    int elem_block = file->elem_block_ids[i];
    char elem_type_name[MAX_NAME_LENGTH+1];
    int num_elem, num_nodes_per_elem, num_faces_per_elem;
    ex_get_block(file->ex_id, EX_ELEM_BLOCK, elem_block, 
                 elem_type_name, &num_elem,
                 &num_nodes_per_elem, NULL,
                 &num_faces_per_elem, NULL);

    // Get the type of element for this block.
    fe_mesh_element_t elem_type = get_element_type(elem_type_name);
    fe_block_t* block = NULL;
    char block_name[MAX_NAME_LENGTH+1];
    if (elem_type == FE_POLYHEDRON)
    {
      // Find the number of faces for each element in the block.
      int* num_elem_faces = polymec_malloc(sizeof(int) * num_elem);
      ex_get_entity_count_per_polyhedra(file->ex_id, EX_ELEM_BLOCK, elem_block, 
                                        num_elem_faces);

      // Get the element->face connectivity.
      int elem_face_size = 0;
      for (int j = 0; j < num_elem; ++j)
        elem_face_size += num_elem_faces[j];
      int* elem_faces = polymec_malloc(sizeof(int) * elem_face_size);
      ex_get_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, NULL, NULL, elem_faces);

      // Subtract 1 from each element face.
      for (int j = 0; j < elem_face_size; ++j)
        elem_faces[j] -= 1;

      // Create the element block.
      block = polyhedral_fe_block_new(num_elem, num_elem_faces, elem_faces);
    }
    else if (elem_type != FE_INVALID)
    {
      // Get the element's nodal mapping.
      int* node_conn = polymec_malloc(sizeof(int) * num_elem * num_nodes_per_elem);
      ex_get_conn(file->ex_id, EX_ELEM_BLOCK, elem_block, node_conn, NULL, NULL);
      
      // Subtract 1 from each element node.
      for (int j = 0; j < num_elem * num_nodes_per_elem; ++j)
        node_conn[j] -= 1;

      // Build the element block.
      block = fe_block_new(num_elem, elem_type, num_nodes_per_elem, node_conn);
    }
    else
    {
      fe_mesh_free(mesh);
      ex_close(file->ex_id);
      polymec_error("Block %d contains an invalid (3D) element type.", elem_block);
    }

    // Fish out the element block name if it has one, or make a default.
    ex_get_name(file->ex_id, EX_ELEM_BLOCK, elem_block, block_name);
    if (strlen(block_name) == 0)
      sprintf(block_name, "block_%d", elem_block);

    // Add the element block to the mesh.
    fe_mesh_add_block(mesh, block_name, block);
  }

  // Fetch node positions and compute geometry.
  real_t x[file->num_nodes], y[file->num_nodes], z[file->num_nodes];
  ex_get_coord(file->ex_id, x, y, z);
  point_t* X = fe_mesh_node_positions(mesh);
  for (int n = 0; n < file->num_nodes; ++n)
  {
    X[n].x = x[n];
    X[n].y = y[n];
    X[n].z = z[n];
  }

  // Fetch sets of entities.
  for (int i = 1; i <= file->num_elem_sets; ++i)
    fetch_set(file, EX_ELEM_SET, i, mesh, fe_mesh_create_element_set);
  for (int i = 1; i <= file->num_face_sets; ++i)
    fetch_set(file, EX_FACE_SET, i, mesh, fe_mesh_create_face_set);
  for (int i = 1; i <= file->num_edge_sets; ++i)
    fetch_set(file, EX_EDGE_SET, i, mesh, fe_mesh_create_edge_set);
  for (int i = 1; i <= file->num_node_sets; ++i)
    fetch_set(file, EX_NODE_SET, i, mesh, fe_mesh_create_node_set);
  for (int i = 1; i <= file->num_side_sets; ++i)
    fetch_set(file, EX_SIDE_SET, i, mesh, fe_mesh_create_side_set);

  return mesh;
}
Example #16
0
static int exchanger_send_message(exchanger_t* ex, void* data, mpi_message_t* msg)
{
  START_FUNCTION_TIMER();
  // If we are expecting data, post asynchronous receives. 
  int j = 0;
  for (int i = 0; i < msg->num_receives; ++i)
  {
    ASSERT(ex->rank != msg->source_procs[i]);
    int err = MPI_Irecv(msg->receive_buffers[i], 
                        msg->stride * msg->receive_buffer_sizes[i],
                        msg->type, msg->source_procs[i], msg->tag, ex->comm, 
                        &(msg->requests[j++]));
    if (err != MPI_SUCCESS)
    {
      int resultlen;
      char str[MPI_MAX_ERROR_STRING];
      MPI_Error_string(err, str, &resultlen);
      char err_msg[1024];
      snprintf(err_msg, 1024, "%d: MPI Error posting receive from %d: %d\n(%s)\n", 
          ex->rank, msg->source_procs[i], err, str);
      polymec_error(err_msg);
    }
  }

  // Send the data asynchronously. 
  for (int i = 0; i < msg->num_sends; ++i)
  {
    int err = MPI_Isend(msg->send_buffers[i], 
                        msg->stride * msg->send_buffer_sizes[i], 
                        msg->type, msg->dest_procs[i], msg->tag, ex->comm, 
                        &(msg->requests[j++])); 
    if (err != MPI_SUCCESS)
    {
      int resultlen;
      char str[MPI_MAX_ERROR_STRING];
      MPI_Error_string(err, str, &resultlen);
      char err_msg[1024];
      snprintf(err_msg, 1024, "%d: MPI Error sending to %d: %d\n(%s)\n", 
          ex->rank, msg->dest_procs[i], err, str);
      polymec_error(err_msg);
    }
  }
  msg->num_requests = j;

  // Allocate a token.
  int token = 0;
  while ((token < ex->num_pending_msgs) && (ex->pending_msgs[token] != NULL))
    ++token;
  if (token == ex->num_pending_msgs) ++ex->num_pending_msgs;
  if (ex->num_pending_msgs == ex->pending_msg_cap)
  {
    ex->pending_msg_cap *= 2;
    ex->pending_msgs = polymec_realloc(ex->pending_msgs, ex->pending_msg_cap*sizeof(mpi_message_t));
    ex->orig_buffers = polymec_realloc(ex->orig_buffers, ex->pending_msg_cap*sizeof(void*));
    ex->transfer_counts = polymec_realloc(ex->transfer_counts, ex->pending_msg_cap*sizeof(int*));
  }
  ex->pending_msgs[token] = msg;
  ex->orig_buffers[token] = data;
  STOP_FUNCTION_TIMER();
  return token;
}
Example #17
0
sp_func_t* rect_prism_new(point_t* x0, 
                          real_t L1, real_t L2, real_t L3,
                          real_t alpha, real_t beta, real_t gamma)
{
  ASSERT(L1 > 0.0);
  ASSERT(L2 > 0.0);
  ASSERT(L3 > 0.0);

  // FOR NOW, we disable Euler angles.
  if ((alpha != 0.0) || (beta != 0.0) || (gamma != 0.0))
    polymec_error("rect_prism_new: Euler angles not yet implemented!");

  // Set the 6 bounding planes.
  vector_t n;
  point_t x;
  sp_func_t* planes[6];

  // "-x" direction
  n.x = 1.0, n.y = 0.0, n.z = 0.0;
  x.x = x0->x - 0.5*L1, x.y = x0->y, x.z = x0->z;
  planes[0] = plane_new(&n, &x);

  // "+x" direction
  n.x = -1.0, n.y = 0.0, n.z = 0.0;
  x.x = x0->x + 0.5*L1, x.y = x0->y, x.z = x0->z;
  planes[1] = plane_new(&n, &x);

  // "-y" direction
  n.x = 0.0, n.y = 1.0, n.z = 0.0;
  x.x = x0->x, x.y = x0->y - 0.5*L2, x.z = x0->z;
  planes[2] = plane_new(&n, &x);

  // "+y" direction
  n.x = 0.0, n.y = -1.0, n.z = 0.0;
  x.x = x0->x, x.y = x0->y + 0.5*L2, x.z = x0->z;
  planes[3] = plane_new(&n, &x);

  // "-z" direction
  n.x = 0.0, n.y = 0.0, n.z = 1.0;
  x.x = x0->x, x.y = x0->y, x.z = x0->z - 0.5*L3;
  planes[4] = plane_new(&n, &x);

  // "+y" direction
  n.x = 0.0, n.y = 0.0, n.z = -1.0;
  x.x = x0->x, x.y = x0->y, x.z = x0->z + 0.5*L3;
  planes[5] = plane_new(&n, &x);

  rect_prism_t* p = polymec_malloc(sizeof(rect_prism_t));
  p->prism = intersection_new(planes, 6);

  // Set up the spatial function.
  sp_func_vtable vtable = {.eval = prism_eval, 
                           .eval_deriv = prism_eval_deriv, 
                           .has_deriv = prism_has_deriv, 
                           .dtor = prism_free};
  char str[1024];
  snprintf(str, 1024, "Rectangular prism (x0 = (%g, %g, %g), L1 = %g, L2 = %g, L3 = %g,"
                      " alpha = %g, beta = %g, gamma = %g)", 
                      x0->x, x0->y, x0->z, L1, L2, L3, alpha, beta, gamma);
  return sp_func_new(str, p, vtable, SP_FUNC_INHOMOGENEOUS, 1);
}