2745 lines
86 KiB
C
2745 lines
86 KiB
C
/*
|
|
Copyright (c) 2006-2012, The Regents of the University of California,
|
|
through Lawrence Berkeley National Laboratory (subject to receipt of any
|
|
required approvals from the U.S. Dept. of Energy) and the Paul Scherrer
|
|
Institut (Switzerland). All rights reserved.
|
|
|
|
License: see file COPYING in top level of source distribution.
|
|
*/
|
|
|
|
#include "h5_errorhandling_private.h"
|
|
#include "h5t_types_private.h"
|
|
#include "h5t_errorhandling_private.h"
|
|
#include "h5t_access_private.h"
|
|
#include "h5t_core_private.h"
|
|
#include "h5t_map_private.h"
|
|
#include "h5t_model_private.h"
|
|
#include "h5t_store_private.h"
|
|
#include "h5t_core_private.h"
|
|
#include "h5t_readwrite_private.h"
|
|
#include "h5_init_private.h"
|
|
#include "h5_mpi_private.h"
|
|
|
|
#include "h5core/h5t_map.h"
|
|
|
|
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
|
|
|
|
int max_num_elems_p_chunk = 120; // minimum is 4 for triangle meshes and
|
|
// 8 for thetrahedral meshes
|
|
|
|
#ifdef PARALLEL_IO
|
|
// that probably doesn't belong here... //TODO put in right place + print variables
|
|
h5_edge_list_t*
|
|
h5tpriv_init_edge_list (
|
|
h5_int32_t num_alloc
|
|
) {
|
|
|
|
h5_edge_list_t* list = NULL;
|
|
list = h5_calloc (1, sizeof (*list));
|
|
list->num_alloc = num_alloc;
|
|
list->num_items = 0;
|
|
list->items = h5_calloc (num_alloc, sizeof (*list->items));
|
|
return list;
|
|
}
|
|
h5_err_t
|
|
h5tpriv_free_edge_list (
|
|
h5_edge_list_t* list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p", list);
|
|
TRY (h5_free (list->items));
|
|
list->items = NULL;
|
|
TRY (h5_free(list));
|
|
list = NULL;
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
h5_err_t
|
|
h5tpriv_grow_edge_list (
|
|
h5_edge_list_t* list,
|
|
h5_int32_t size
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p", list);
|
|
assert (list->num_alloc + size >= 0);
|
|
if (size < 0) {
|
|
h5_debug ("Warning: you are shrinking the edge_list!");
|
|
}
|
|
if (size == 0) {
|
|
h5_debug ("Warning: you are not growing the edge_list!");
|
|
}
|
|
TRY ( list->items = h5_alloc(list->items, (list->num_alloc + size) * sizeof (*list->items)));
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* compare edge_list_elem
|
|
*/
|
|
int compare_edge_list_elem(const void *p_a, const void *p_b) {
|
|
h5t_edge_list_elem_t* elem_a = ((h5t_edge_list_elem_t*) p_a);
|
|
h5t_edge_list_elem_t* elem_b = ((h5t_edge_list_elem_t*) p_b);
|
|
|
|
if (elem_a->vtx1 - elem_b->vtx1 != 0) {
|
|
return elem_a->vtx1 - elem_b->vtx1;
|
|
} else {
|
|
if (elem_a->vtx2 - elem_b->vtx2 != 0) {
|
|
return elem_a->vtx2 - elem_b->vtx2;
|
|
}
|
|
}
|
|
return elem_a->proc - elem_b->proc;
|
|
}
|
|
h5_err_t
|
|
h5tpriv_uniquify_edge_list (
|
|
h5_edge_list_t* list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p", list);
|
|
if (list->num_items == 0) {
|
|
H5_PRIV_FUNC_LEAVE (H5_SUCCESS);
|
|
}
|
|
h5t_edge_list_elem_t* old_elem = list->items;
|
|
int num_old_elems = list->num_items;
|
|
list->items = h5_calloc (list->num_alloc, sizeof (*list->items));
|
|
memcpy (&list->items[0], &old_elem[0], sizeof (*list->items));
|
|
list->num_items = 1;
|
|
for (int i = 1; i < num_old_elems; i++) {
|
|
int comp = compare_edge_list_elem (&list->items[list->num_items-1], &old_elem[i] );
|
|
if (comp > 0) { // element in old_elem is smaller then last elem in list
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INVAL); // probably list wasn't sorted
|
|
}
|
|
if (comp < 0) {
|
|
memcpy (&list->items[list->num_items++], &old_elem[i], sizeof (*list->items));
|
|
}
|
|
}
|
|
TRY (h5_free (old_elem));
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5tpriv_sort_edge_list (
|
|
h5_edge_list_t* list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p", list);
|
|
qsort(list->items,list->num_items, sizeof (*list->items), compare_edge_list_elem);
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
|
|
h5_int32_t
|
|
h5tpriv_find_edge_list (
|
|
h5_edge_list_t* list,
|
|
h5t_edge_list_elem_t* elem
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p", list);
|
|
|
|
comparison_fn_t comp_func;
|
|
comp_func.compare = compare_edge_list_elem;
|
|
// need linear search because we want to know first elem that hits.
|
|
h5t_edge_list_elem_t* retval = linsearch (elem, list->items ,list->num_items, sizeof (*list->items), comp_func);
|
|
if (retval == NULL) {
|
|
H5_PRIV_FUNC_LEAVE (list->num_items);
|
|
}
|
|
H5_PRIV_FUNC_RETURN (retval - list->items); // TODO check if that works
|
|
}
|
|
h5_err_t
|
|
h5tpriv_add_edge_list (
|
|
h5_edge_list_t* list,
|
|
h5_glb_idx_t vtx1,
|
|
h5_glb_idx_t vtx2,
|
|
h5_loc_idx_t new_vtx,
|
|
h5_int32_t proc
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p", list);
|
|
h5t_edge_list_elem_t elem;
|
|
elem.vtx1 = vtx1 < vtx2 ? vtx1 : vtx2; // vtx1 < vtx2 always!
|
|
elem.vtx2 = vtx1 > vtx2 ? vtx1 : vtx2;
|
|
elem.new_vtx = (h5_glb_idx_t) new_vtx; // problem => first we would like to store loc_idx and later the glb_idx therefore cast here
|
|
// alternative would be to store two variables...
|
|
elem.proc = -1;
|
|
|
|
// add edge
|
|
if (list->num_alloc == list->num_items) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INVAL);
|
|
}
|
|
list->items[list->num_items].vtx1 = elem.vtx1;
|
|
list->items[list->num_items].vtx2 = elem.vtx2;
|
|
list->items[list->num_items].new_vtx = elem.new_vtx;
|
|
list->items[list->num_items++].proc = proc;
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
//END TODO put in right place + print variables
|
|
|
|
h5_err_t
|
|
h5tpriv_calc_chunk_statistic (
|
|
h5t_mesh_t* const m,
|
|
FILE* file
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
if (file == NULL || m->chunks == NULL) {
|
|
H5_PRIV_FUNC_LEAVE (H5_SUCCESS);
|
|
}
|
|
fprintf (file, "# printing chunk statistics of file \n");
|
|
fprintf (file, "# num_levels level max_elem num_chunks elems_p_level minfill maxfill avg_p_level avg_fill_p_level \n");
|
|
int counter = 0;
|
|
h5_glb_idx_t* num_elems_p_level = NULL;
|
|
TRY (num_elems_p_level = h5_calloc (m->chunks->num_levels +1, sizeof (*num_elems_p_level)));
|
|
h5_glb_idx_t* min_elems_p_level = NULL;
|
|
TRY (min_elems_p_level = h5_calloc (m->chunks->num_levels +1, sizeof (*min_elems_p_level)));
|
|
h5_glb_idx_t* max_elems_p_level = NULL;
|
|
TRY (max_elems_p_level = h5_calloc (m->chunks->num_levels +1, sizeof (*max_elems_p_level)));
|
|
h5_float64_t* avg_p_level = NULL;
|
|
TRY (avg_p_level = h5_calloc (m->chunks->num_levels +1, sizeof (*avg_p_level)));
|
|
h5_float64_t* avgfill_p_level = NULL;
|
|
TRY (avgfill_p_level = h5_calloc (m->chunks->num_levels +1, sizeof (*avg_p_level)));
|
|
min_elems_p_level[ m->chunks->num_levels] = m->chunks->chunks[counter].num_elems;
|
|
max_elems_p_level[ m->chunks->num_levels] = m->chunks->chunks[counter].num_elems;
|
|
for (int i = 0; i < m->chunks->num_levels; i++) {
|
|
// calc avg
|
|
min_elems_p_level[i] = m->chunks->chunks[counter].num_elems;
|
|
max_elems_p_level[i] = m->chunks->chunks[counter].num_elems;
|
|
for (int j = 0; j < m->chunks->num_chunks_p_level[i]; j++) {
|
|
num_elems_p_level[i] += m->chunks->chunks[counter].num_elems;
|
|
num_elems_p_level[m->chunks->num_levels] += m->chunks->chunks[counter].num_elems;
|
|
min_elems_p_level[i] > m->chunks->chunks[counter].num_elems ? min_elems_p_level[i] = m->chunks->chunks[counter].num_elems : 0;
|
|
max_elems_p_level[i] < m->chunks->chunks[counter].num_elems ? max_elems_p_level[i] = m->chunks->chunks[counter].num_elems : 0;
|
|
counter++;
|
|
}
|
|
avg_p_level[i] = num_elems_p_level[i] / (double) m->chunks->num_chunks_p_level[i];
|
|
avgfill_p_level[i] = avg_p_level[i] / max_num_elems_p_chunk;
|
|
min_elems_p_level[m->chunks->num_levels] > min_elems_p_level[i] ? min_elems_p_level[m->chunks->num_levels] = min_elems_p_level[i] : 0;
|
|
max_elems_p_level[m->chunks->num_levels] < max_elems_p_level[i] ? max_elems_p_level[m->chunks->num_levels] = max_elems_p_level[i] : 0;
|
|
}
|
|
avg_p_level[m->chunks->num_levels] = num_elems_p_level[m->chunks->num_levels] / (double) counter;
|
|
avgfill_p_level[m->chunks->num_levels] = avg_p_level[m->chunks->num_levels] / max_num_elems_p_chunk;
|
|
for (int i = 0; i <= m->chunks->num_levels; i++) {
|
|
if (i == m->chunks->num_levels) {
|
|
fprintf (file, " %6d %6d %9d %9d %10lld %10lld %10lld %10.4f %10.4f #avg over whole mesh\n\n",
|
|
m->chunks->num_levels, i, max_num_elems_p_chunk, counter,
|
|
(long long int) num_elems_p_level[i],(long long int)min_elems_p_level[i],
|
|
(long long int)max_elems_p_level[i],avg_p_level[i],avgfill_p_level[i]);
|
|
} else {
|
|
fprintf (file, " %6d %6d %9d %9d %10lld %10lld %10lld %10.4f %10.4f \n",
|
|
m->chunks->num_levels, i, max_num_elems_p_chunk, m->chunks->num_chunks_p_level[i],
|
|
(long long int) num_elems_p_level[i],(long long int)min_elems_p_level[i],
|
|
(long long int)max_elems_p_level[i],avg_p_level[i],avgfill_p_level[i]);
|
|
}
|
|
|
|
}
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* Calculate the global vertex range for the new vertices
|
|
* range[i] = first glb idx of proc i
|
|
* range[nproc] = next glb idx to assign
|
|
*/
|
|
h5_err_t
|
|
h5tpriv_get_vtx_ranges (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idx_t* range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, range=%p", m, range);
|
|
h5_glb_idx_t sendbuf = m->last_stored_vid - m->last_stored_vid_before_ref;
|
|
|
|
TRY (h5priv_mpi_allgather (
|
|
&sendbuf,
|
|
1,
|
|
MPI_LONG,
|
|
&range[1],
|
|
1,
|
|
MPI_LONG,
|
|
m->f->props->comm));
|
|
|
|
// set start of new vtx idx (because if leaf_level != 0 it was increased already)
|
|
if (m->leaf_level == 0) {
|
|
range[0] = 0;
|
|
} else {
|
|
range[0] = m->num_glb_vertices[m->leaf_level-1];
|
|
}
|
|
// calc range
|
|
for (int i = 1; i <= m->f->nprocs; i++) {
|
|
range[i] += range[i-1];
|
|
}
|
|
|
|
if (m->leaf_level == 0) {
|
|
m->num_glb_vertices[0] = range[m->f->myproc];
|
|
} else {
|
|
m->num_glb_vertices[m->leaf_level-1] = range[m->f->myproc];
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
#endif
|
|
/*
|
|
Assign unique global indices to vertices.
|
|
*/
|
|
static h5_err_t
|
|
assign_global_vertex_indices (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
h5_loc_idx_t local_idx = (m->leaf_level == 0) ?
|
|
0 : m->num_loc_vertices[m->leaf_level-1];
|
|
|
|
|
|
#ifdef PARALLEL_IO
|
|
// exchange num vertices and calc range
|
|
h5_glb_idx_t* range = NULL;
|
|
TRY (range = h5_calloc (m->f->nprocs + 1, sizeof (*range)));
|
|
TRY (h5tpriv_get_vtx_ranges (m, range));
|
|
int counter = 0;
|
|
for (;local_idx < m->num_loc_vertices[m->num_leaf_levels-1];
|
|
local_idx++, counter++) {
|
|
m->vertices[local_idx].idx = range[m->f->myproc] + counter;
|
|
}
|
|
if (counter + range[m->f->myproc] != range[m->f->myproc + 1]) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
TRY (h5_free (range));
|
|
#else
|
|
/*
|
|
simple in serial runs: global_id = local_id
|
|
*/
|
|
|
|
for (;
|
|
local_idx < m->num_loc_vertices[m->num_leaf_levels-1];
|
|
local_idx++) {
|
|
m->vertices[local_idx].idx = local_idx;
|
|
}
|
|
#endif
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* there is a different version needed for after the refinement because
|
|
* not all vertices need to get a glb_idx from this proc
|
|
*/
|
|
|
|
static h5_err_t
|
|
assign_global_vertex_indices_chk (
|
|
h5t_mesh_t* const m,
|
|
h5_loc_idxlist_t* vtx_list, // list with vertices that don't need to be assigned
|
|
h5_glb_idx_t* vtx_range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, vtx_list=%p, vtx_range=%p", m, vtx_list, vtx_range);
|
|
h5_loc_idx_t local_idx = (m->leaf_level == 0) ?
|
|
0 : m->num_loc_vertices[m->leaf_level-1]; // should not be 0 since only after ref...
|
|
|
|
int counter = 0;
|
|
for (;local_idx < m->num_loc_vertices[m->num_leaf_levels-1];
|
|
local_idx++) {
|
|
|
|
h5_loc_idx_t retval = h5priv_find_in_loc_idxlist (vtx_list, local_idx);
|
|
if (retval < 0) {
|
|
// idx needs to be assigned.
|
|
m->vertices[local_idx].idx = vtx_range[m->f->myproc] + counter;
|
|
counter++;
|
|
}
|
|
}
|
|
if (counter + vtx_range[m->f->myproc] != vtx_range[m->f->myproc + 1]) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*!
|
|
Assign unique global indices to new elements.
|
|
*/
|
|
static h5_err_t
|
|
assign_glb_elem_indices (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
/*
|
|
simple in serial runs: global index = local index
|
|
*/
|
|
h5_loc_idx_t loc_idx = (m->leaf_level == 0) ? 0 : m->num_interior_elems[m->leaf_level-1];
|
|
|
|
for (; loc_idx < m->num_interior_elems[m->leaf_level]; loc_idx++) {
|
|
h5tpriv_set_loc_elem_glb_idx (m, loc_idx, loc_idx);
|
|
}
|
|
|
|
return H5_SUCCESS;
|
|
}
|
|
|
|
/*!
|
|
Assign unique global indices to new elements.
|
|
*/
|
|
static h5_err_t
|
|
assign_glb_elem_indices_chk ( //TODO use ifdef instead of new func name
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idx_t* range
|
|
) {
|
|
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, range=%p", m, range);
|
|
|
|
h5_loc_idx_t loc_idx = (m->leaf_level == 0) ? 0 : m->num_interior_elems[m->leaf_level-1];
|
|
int counter = 0;
|
|
for (; loc_idx < m->num_interior_elems[m->leaf_level]; loc_idx++, counter++) {
|
|
h5tpriv_set_loc_elem_glb_idx (m, loc_idx, range[m->f->myproc] + counter);
|
|
}
|
|
|
|
if (counter + range[m->f->myproc] != range[m->f->myproc + 1]) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
|
|
}
|
|
|
|
|
|
h5_lvl_idx_t
|
|
h5tpriv_add_level (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_lvl_idx_t, "m=%p", m);
|
|
CHECK_WRITABLE_MODE(m->f);
|
|
|
|
m->leaf_level = m->num_leaf_levels++;
|
|
m->num_loaded_levels = m->num_leaf_levels;
|
|
|
|
TRY (m->num_glb_vertices = h5_alloc (m->num_glb_vertices, m->num_leaf_levels*sizeof (*m->num_glb_vertices)));
|
|
TRY (m->num_loc_vertices = h5_alloc (m->num_loc_vertices, m->num_leaf_levels*sizeof (*m->num_loc_vertices)));
|
|
|
|
TRY (m->num_b_vtx = h5_alloc (m->num_b_vtx, m->num_leaf_levels*sizeof (*m->num_b_vtx)));
|
|
TRY (m->first_b_vtx = h5_alloc (m->first_b_vtx, m->num_leaf_levels*sizeof (*m->first_b_vtx)));
|
|
|
|
TRY (m->num_glb_elems = h5_alloc (m->num_glb_elems, m->num_leaf_levels*sizeof (*m->num_glb_elems)));
|
|
TRY (m->num_glb_leaf_elems = h5_alloc (m->num_glb_leaf_elems, m->num_leaf_levels*sizeof (*m->num_glb_leaf_elems)));
|
|
TRY (m->num_interior_elems = h5_alloc (m->num_interior_elems, m->num_leaf_levels*sizeof (*m->num_interior_elems)));
|
|
TRY (m->num_interior_leaf_elems = h5_alloc (m->num_interior_leaf_elems, m->num_leaf_levels*sizeof (*m->num_interior_leaf_elems)));
|
|
TRY (m->num_ghost_elems = h5_alloc (m->num_ghost_elems, m->num_leaf_levels*sizeof (*m->num_ghost_elems)));
|
|
|
|
m->num_glb_vertices[m->leaf_level] = -1;
|
|
m->num_loc_vertices[m->leaf_level] = -1;
|
|
|
|
m->num_glb_elems[m->leaf_level] = -1;
|
|
m->num_glb_leaf_elems[m->leaf_level] = -1;
|
|
m->num_interior_elems[m->leaf_level] = -1;
|
|
m->num_interior_leaf_elems[m->leaf_level] = -1;
|
|
m->num_ghost_elems[m->leaf_level] = 0;
|
|
|
|
if (m->leaf_level == 0) {
|
|
/* nothing stored yet */
|
|
m->last_stored_vid = -1;
|
|
m->last_stored_eid = -1;
|
|
m->last_stored_vid_before_ref = -1;
|
|
m->last_stored_eid_before_ref = -1;
|
|
} else {
|
|
assert (m->last_stored_vid == m->num_loc_vertices[m->leaf_level - 1] - 1);
|
|
assert (m->last_stored_eid == m->num_interior_elems[m->leaf_level - 1] - 1);
|
|
}
|
|
|
|
H5_CORE_API_RETURN (m->leaf_level);
|
|
}
|
|
|
|
/*!
|
|
Allocate memory for (more) vertices.
|
|
*/
|
|
h5_err_t
|
|
h5t_begin_store_vertices (
|
|
h5t_mesh_t* const m,
|
|
const h5_size_t num
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p, num=%llu", m, (long long unsigned)num);
|
|
if (m->leaf_level < 0) {
|
|
H5_CORE_API_LEAVE (h5tpriv_error_undef_level());
|
|
}
|
|
h5_size_t cur_num_loc_vertices = (m->leaf_level > 0 ?
|
|
m->num_loc_vertices[m->leaf_level-1] : 0);
|
|
m->last_stored_vid = cur_num_loc_vertices - 1;
|
|
m->last_stored_vid_before_ref = m->last_stored_vid;
|
|
m->num_loc_vertices[m->leaf_level] = cur_num_loc_vertices+num;
|
|
m->dsinfo_vertices.dims[0] = cur_num_loc_vertices+num;
|
|
H5_CORE_API_RETURN (h5tpriv_alloc_loc_vertices (m, cur_num_loc_vertices+num));
|
|
}
|
|
|
|
h5_loc_idx_t
|
|
h5t_store_vertex (
|
|
h5t_mesh_t* const m, /*!< file handle */
|
|
const h5_glb_idx_t glb_id, /*!< global vertex id from mesher or -1 */
|
|
const h5_float64_t P[3] /*!< coordinates */
|
|
) {
|
|
H5_CORE_API_ENTER (h5_loc_idx_t,
|
|
"m=%p, glb=id=%lld, P=%p",
|
|
m,
|
|
(long long)glb_id,
|
|
P);
|
|
|
|
// more than allocated
|
|
if (m->last_stored_vid+1 >= m->num_loc_vertices[m->leaf_level])
|
|
H5_CORE_API_LEAVE (HANDLE_H5_OVERFLOW_ERR(
|
|
m->num_loc_vertices[m->leaf_level]));
|
|
|
|
h5_loc_idx_t local_idx = ++m->last_stored_vid;
|
|
h5_loc_vertex_t *vertex = &m->vertices[local_idx];
|
|
vertex->idx = glb_id; /* ID from mesher, replaced later!*/
|
|
memcpy (&vertex->P, P, sizeof (vertex->P));
|
|
H5_CORE_API_RETURN (local_idx);
|
|
}
|
|
|
|
h5_err_t
|
|
h5t_end_store_vertices (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
m->num_loc_vertices[m->leaf_level] = m->last_stored_vid+1;
|
|
TRY (assign_global_vertex_indices (m));
|
|
TRY (h5tpriv_rebuild_map_vertex_g2l_partial (m));
|
|
m->last_stored_vid_before_ref = -1;
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*!
|
|
Initialize everything so that we can begin to store elements.
|
|
|
|
\param[in] f file handle
|
|
\param[in] num number of elements to add
|
|
*/
|
|
h5_err_t
|
|
h5t_begin_store_elems (
|
|
h5t_mesh_t* const m,
|
|
const h5_size_t num,
|
|
const h5_weight_t num_weights
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t,
|
|
"m=%p, num=%llu, num_weights=%d",
|
|
m, (long long unsigned)num, num_weights);
|
|
|
|
h5_debug ("begin storing %llu elements", (long long)num);
|
|
size_t cur = m->leaf_level > 0 ? m->num_interior_elems[m->leaf_level-1] : 0;
|
|
m->last_stored_eid = cur - 1;
|
|
size_t new = num + cur;
|
|
m->dsinfo_elems.dims[0] = new;
|
|
|
|
m->num_interior_elems[m->leaf_level] = new;
|
|
|
|
m->num_interior_leaf_elems[m->leaf_level] = m->leaf_level > 0 ?
|
|
num + m->num_interior_leaf_elems[m->leaf_level-1] : num;
|
|
|
|
m->num_weights = num_weights;
|
|
if (m->leaf_level == 0) {
|
|
TRY (m->weights = h5_calloc(num_weights * num, sizeof (* m->weights) ));
|
|
if (m->num_weights < 1) {
|
|
m->weights = NULL;
|
|
}
|
|
} else {
|
|
// we don't now how many glb elems -> alloc needs to be later
|
|
}
|
|
|
|
m->last_stored_eid_before_ref = m->last_stored_eid;
|
|
|
|
H5_CORE_API_RETURN (h5tpriv_alloc_loc_elems (m, cur, new));
|
|
}
|
|
|
|
|
|
/*!
|
|
Store element. The vertices are given via their local indices.
|
|
|
|
\param[in] f File handle.
|
|
\param[in] elem_idx_of_parent Local indexd of the parent element
|
|
or \c -1.
|
|
\param[in] vertices Local vertex indices defining the
|
|
tetrahedron.
|
|
*/
|
|
h5_loc_idx_t
|
|
h5t_store_elem (
|
|
h5t_mesh_t* const m,
|
|
const h5_loc_idx_t parent_idx,
|
|
const h5_loc_idx_t* vertex_indices,
|
|
const h5_weight_t* weights
|
|
) {
|
|
H5_CORE_API_ENTER (h5_loc_idx_t,
|
|
"m=%p, parent_idx=%lld, vertex_indices=%p, weights=%p",
|
|
m,
|
|
(long long)parent_idx,
|
|
vertex_indices,
|
|
weights);
|
|
|
|
/* more than allocated? */
|
|
if ( m->last_stored_eid+1 >= m->num_interior_elems[m->leaf_level] )
|
|
H5_CORE_API_LEAVE (
|
|
HANDLE_H5_OVERFLOW_ERR (m->num_interior_elems[m->leaf_level]));
|
|
|
|
/* check parent id */
|
|
if ((m->leaf_level == 0 && parent_idx != -1) ||
|
|
(m->leaf_level > 0 && parent_idx < 0) ||
|
|
(m->leaf_level > 0
|
|
&& parent_idx >= m->num_interior_elems[m->leaf_level-1])
|
|
) {
|
|
H5_CORE_API_LEAVE (
|
|
HANDLE_H5_PARENT_ID_ERR (parent_idx));
|
|
}
|
|
|
|
/* store elem data (but neighbors) */
|
|
h5_loc_idx_t elem_idx = ++m->last_stored_eid;
|
|
h5tpriv_set_loc_elem_parent_idx (m, elem_idx, parent_idx);
|
|
h5tpriv_set_loc_elem_child_idx (m, elem_idx, -1);
|
|
h5tpriv_set_loc_elem_level_idx (m, elem_idx, m->leaf_level);
|
|
|
|
// get ptr to local vertices store
|
|
h5_loc_idx_t* loc_vertex_indices = h5tpriv_get_loc_elem_vertex_indices (
|
|
m, elem_idx);
|
|
int num_vertices = h5tpriv_ref_elem_get_num_vertices (m);
|
|
memcpy (loc_vertex_indices, vertex_indices,
|
|
sizeof (*vertex_indices)*num_vertices);
|
|
|
|
|
|
if (m->leaf_level > 0) {
|
|
/* add edges to map edges -> elements */
|
|
h5_loc_idx_t face_idx;
|
|
int num_faces = h5tpriv_ref_elem_get_num_edges (m);
|
|
for (face_idx = 0; face_idx < num_faces; face_idx++) {
|
|
// add edges to neighbour struct
|
|
TRY (h5tpriv_enter_te2 (m, face_idx, elem_idx, NULL));
|
|
}
|
|
}
|
|
if (weights != NULL && m->leaf_level == 0) {
|
|
memcpy (&m->weights[elem_idx * m->num_weights], weights, sizeof (*m->weights) * m->num_weights);
|
|
for (int i = 0; i < m->num_weights; i++) {
|
|
if (m->weights[elem_idx * m->num_weights + i] < 1) {
|
|
m->weights[elem_idx * m->num_weights + i] = 1;
|
|
}
|
|
}
|
|
}
|
|
H5_CORE_API_RETURN (elem_idx);
|
|
}
|
|
h5_loc_idx_t
|
|
h5t_store_elem2 (
|
|
h5t_mesh_t* const m,
|
|
const h5_loc_idx_t parent_idx,
|
|
const h5_loc_idx_t* vertex_indices,
|
|
const h5_weight_t* weights
|
|
) {
|
|
H5_CORE_API_ENTER (h5_loc_idx_t,
|
|
"m=%p, parent_idx=%lld, vertex_indices=%p, weights=%p",
|
|
m,
|
|
(long long)parent_idx,
|
|
vertex_indices,
|
|
weights);
|
|
h5t_store_elem (m, parent_idx, vertex_indices, weights);
|
|
h5_loc_idx_t* loc_vertex_indices = h5tpriv_get_loc_elem_vertex_indices (
|
|
m, m->last_stored_eid);
|
|
int num_vertices = h5tpriv_ref_elem_get_num_vertices (m);
|
|
TRY (h5tpriv_sort_local_vertex_indices (m, loc_vertex_indices, num_vertices));
|
|
H5_CORE_API_RETURN (m->last_stored_eid);
|
|
}
|
|
/*
|
|
Rebuild mapping of global element indices to their local indices.
|
|
*/
|
|
h5_err_t
|
|
rebuild_map_elem_g2l (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
if (m->num_leaf_levels <= 0) H5_PRIV_API_LEAVE (H5_SUCCESS);
|
|
|
|
h5_idxmap_t* map = &m->map_elem_g2l;
|
|
h5_loc_idx_t loc_idx = m->leaf_level > 0 ? m->num_interior_elems[m->leaf_level-1] : 0;
|
|
h5_loc_idx_t num_interior_elems = m->num_interior_elems[m->num_leaf_levels-1];
|
|
|
|
/* (re-)alloc mem for global to local ID mapping */
|
|
TRY (h5priv_grow_idxmap (map, num_interior_elems));
|
|
|
|
h5_idxmap_el_t *item = &map->items[loc_idx];
|
|
for (; loc_idx < num_interior_elems; loc_idx++, item++) {
|
|
item->glb_idx = h5tpriv_get_loc_elem_glb_idx (m, loc_idx);
|
|
item->loc_idx = loc_idx;
|
|
map->num_items++;
|
|
}
|
|
h5priv_sort_idxmap (map);
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
Rebuild mapping of global element indices to their local indices.
|
|
*/
|
|
h5_err_t
|
|
rebuild_map_elem_g2l_partial ( // we need that to update map for the refined elems before we have the
|
|
// refined elements from the other proces
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
if (m->num_leaf_levels <= 0) H5_PRIV_API_LEAVE (H5_SUCCESS);
|
|
|
|
h5_idxmap_t* map = &m->map_elem_g2l;
|
|
h5_loc_idx_t loc_idx = m->last_stored_eid_before_ref +1;
|
|
h5_loc_idx_t num_interior_elems = m->last_stored_eid - m->last_stored_eid_before_ref;
|
|
|
|
/* (re-)alloc mem for global to local ID mapping */
|
|
TRY (h5priv_grow_idxmap (map, map->size + num_interior_elems));
|
|
|
|
h5_idxmap_el_t *item = &map->items[loc_idx];
|
|
for (; loc_idx <= m->last_stored_eid ; loc_idx++, item++) {
|
|
item->glb_idx = h5tpriv_get_loc_elem_glb_idx (m, loc_idx);
|
|
item->loc_idx = loc_idx;
|
|
map->num_items++;
|
|
}
|
|
assert (map->size >= map->num_items);
|
|
h5priv_sort_idxmap (map);
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5t_end_store_elems (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
h5_debug ("end storing elements");
|
|
m->num_interior_elems[m->leaf_level] = m->last_stored_eid+1;
|
|
m->num_glb_elems[m->leaf_level] = m->last_stored_eid+1;
|
|
m->num_glb_leaf_elems[m->leaf_level] = m->num_interior_leaf_elems[m->leaf_level];
|
|
m->last_stored_eid_before_ref = -1;
|
|
|
|
/* assign global indices to new indices */
|
|
TRY (assign_glb_elem_indices (m));
|
|
|
|
/* rebuild map: global index -> local_index */
|
|
TRY (rebuild_map_elem_g2l (m));
|
|
|
|
/* mesh specific finalize */
|
|
TRY (m->methods->store->end_store_elems (m));
|
|
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* linear search trough chunks to find chk_idx which contains element
|
|
*/
|
|
static h5_err_t
|
|
h5tpriv_find_chk_of_elem (
|
|
h5t_mesh_t* m,
|
|
h5_loc_id_t id,
|
|
h5_chk_idx_t* chk_idx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, id=%lld, chk_idx=%p", m, (long long int)id, chk_idx);
|
|
h5_glb_idx_t glb_idx = h5tpriv_get_loc_elem_glb_idx (m, h5tpriv_get_elem_idx (id));
|
|
|
|
// calc total num chunks
|
|
h5_chk_idx_t total_num_chunks = 0;
|
|
for (int i = 0; i < m->chunks->num_levels; i++) {
|
|
total_num_chunks += m->chunks->num_chunks_p_level[i];
|
|
}
|
|
for (h5_chk_idx_t i = 0; i < total_num_chunks; i++) {
|
|
if (glb_idx >= m->chunks->chunks[i].elem &&
|
|
glb_idx < m->chunks->chunks[i].elem + m->chunks->chunks[i].num_elems) {
|
|
// elem is contained in chunk
|
|
*chk_idx = i;
|
|
H5_PRIV_FUNC_LEAVE (H5_SUCCESS);
|
|
}
|
|
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_ERR_INVAL);
|
|
}
|
|
/*
|
|
* compare chk_idx
|
|
*/
|
|
int compare_vtx_chk_list(const void *p_a, const void *p_b) {
|
|
return ((h5t_vtx_chk_list_t*) p_a)->chk - ((h5t_vtx_chk_list_t*) p_b)->chk;
|
|
}
|
|
|
|
#ifdef CHUNKING_OF_VTX
|
|
static h5_err_t
|
|
h5tpriv_calc_vtx_permutation (
|
|
h5t_mesh_t* m,
|
|
h5t_vtx_chk_list_t* permut
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, permut=%p", m, permut);
|
|
h5t_vtx_chk_list_t* b_vtx = NULL; // boundary vertices
|
|
TRY (b_vtx = h5_calloc (m->num_loc_vertices[m->leaf_level], sizeof (*b_vtx)));
|
|
memset (b_vtx, -1,m->num_loc_vertices[m->leaf_level]*sizeof (*b_vtx));
|
|
|
|
h5_chk_idx_t* chk_idx_of_vtx = NULL; // allows us also to sort vtx acc to chunks
|
|
TRY (chk_idx_of_vtx = h5_calloc (m->num_loc_vertices[m->leaf_level], sizeof (*chk_idx_of_vtx)));
|
|
h5_loc_idx_t counter = 0;
|
|
h5_loc_idx_t b_counter = 0;
|
|
h5_loc_idlist_t* list = NULL;
|
|
|
|
|
|
for (h5_loc_idx_t i = 0; i < m->num_loc_vertices[m->leaf_level]; i++) {
|
|
// get list of elems for vertex i
|
|
TRY (h5tpriv_find_tv3 (m, i, &list));
|
|
h5_chk_idx_t old_chk_idx = -1;
|
|
h5_chk_idx_t chk_idx = -1;
|
|
int done = 0;
|
|
for (int j = 0; j < list->num_items; j++) {
|
|
TRY ( h5tpriv_find_chk_of_elem (m, list->items[j], &chk_idx));
|
|
if (j == 0) {
|
|
old_chk_idx = chk_idx;
|
|
}
|
|
if (old_chk_idx != chk_idx) {
|
|
// vtx is a chunk boundary vtx
|
|
b_vtx[b_counter++].vtx = i;
|
|
done = 1;
|
|
break;
|
|
}
|
|
|
|
}
|
|
if (!done) {
|
|
// vtx is a inner chunk vtx
|
|
permut[counter].vtx = i;
|
|
permut[counter++].chk = chk_idx;
|
|
}
|
|
}
|
|
if (counter + b_counter != m->num_loc_vertices[m->leaf_level]) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
// sort vtx acc to chunk
|
|
qsort (permut, counter, sizeof (*permut), compare_vtx_chk_list);
|
|
|
|
memcpy (&permut[counter], b_vtx, b_counter * sizeof (*permut));
|
|
|
|
m->num_b_vtx[0] = b_counter;
|
|
m->first_b_vtx[0] = counter;
|
|
|
|
TRY (h5_free (b_vtx));
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* calculate the reverse permutation access old_idx gives new_idx
|
|
*/
|
|
static h5_err_t
|
|
h5tpriv_calc_vtx_revpermutation (
|
|
h5t_mesh_t* m,
|
|
h5t_vtx_chk_list_t* permut,
|
|
h5t_vtx_chk_list_t* rev_permut
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, permut=%p, rev_permut=%p", m, permut, rev_permut);
|
|
for (int i = 0; i < m->num_loc_vertices[m->leaf_level]; i++) {
|
|
h5_loc_idx_t vtx = permut[i].vtx;
|
|
rev_permut[vtx].vtx = i;
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
#endif // CHUNKING_OF_VTX
|
|
|
|
// used to chunk vtx
|
|
//static h5_err_t
|
|
//h5tpriv_store_vtx_range_to_chk (
|
|
// h5t_mesh_t* m,
|
|
// h5t_vtx_chk_list_t* permut
|
|
// ) {
|
|
// H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, permut=%p", m, permut);
|
|
// assert (m->f->nprocs == 1);
|
|
// int counter = 0;
|
|
// h5_chk_idx_t chk_idx = -1;
|
|
// h5_glb_idx_t first_vtx = -1;
|
|
// for (int i = 0; i < m->num_loc_vertices[m->leaf_level]; i++) {
|
|
// first_vtx = i;
|
|
// chk_idx = permut[i].chk;
|
|
// counter = 1;
|
|
// while (i + 1 < m->num_loc_vertices[m->leaf_level] && chk_idx == permut[i+1].chk) {
|
|
// counter++;
|
|
// i++;
|
|
// }
|
|
// if (chk_idx != -1) {
|
|
// m->chunks->chunks[chk_idx].vtx = first_vtx;
|
|
// m->chunks->chunks[chk_idx].num_vtx = counter;
|
|
// }
|
|
// }
|
|
// H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
//}
|
|
|
|
|
|
h5_err_t
|
|
h5t_end_store_ckd_elems (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
h5_debug ("end storing elements");
|
|
#ifdef PARALLEL_IO
|
|
m->num_interior_elems[m->leaf_level] = m->last_stored_eid+1;
|
|
m->num_glb_elems[m->leaf_level] = m->last_stored_eid+1;// only works for serial case
|
|
m->num_glb_leaf_elems[m->leaf_level] = m->num_interior_leaf_elems[m->leaf_level];
|
|
|
|
if (m->leaf_level == 0) {
|
|
// calculate midpoints of elements
|
|
h5_oct_point_t* midpoints;
|
|
TRY (midpoints = h5_calloc (m->num_glb_elems[0], sizeof (*midpoints)));
|
|
h5_loc_idx_t curr_midp = 0;
|
|
|
|
h5_float64_t bb[6]; // for calculating bounding box
|
|
int num_faces = h5tpriv_ref_elem_get_num_edges (m);
|
|
int num_vertices = h5tpriv_ref_elem_get_num_vertices (m);
|
|
|
|
for (h5_loc_idx_t i = 0; i < m->num_glb_elems[0]; i++) {
|
|
h5_loc_idx_t* indices; //[4] = {-1, -1, -1, -1};
|
|
indices = h5tpriv_get_loc_elem_vertex_indices (m, i);
|
|
h5_float64_t midpoint[3] = {0, 0, 0};
|
|
h5_float64_t P[3];
|
|
|
|
for (int j = 0; j < num_vertices; j++) {
|
|
TRY (h5t_get_vertex_coords_by_index (m, indices[j], P));
|
|
midpoint[0] += P[0];
|
|
midpoint[1] += P[1];
|
|
midpoint[2] += P[2];
|
|
if (i == 0 && j == 0) {
|
|
bb[0] = P[0];
|
|
bb[1] = P[1];
|
|
bb[2] = P[2];
|
|
bb[3] = P[0];
|
|
bb[4] = P[1];
|
|
bb[5] = P[2];
|
|
} else {
|
|
bb[0] = (P[0] < bb[0]) ? P[0] : bb[0];
|
|
bb[1] = (P[1] < bb[1]) ? P[1] : bb[1];
|
|
bb[2] = (P[2] < bb[2]) ? P[2] : bb[2];
|
|
bb[3] = (P[0] > bb[3]) ? P[0] : bb[3];
|
|
bb[4] = (P[1] > bb[4]) ? P[1] : bb[4];
|
|
bb[5] = (P[2] > bb[5]) ? P[2] : bb[5];
|
|
}
|
|
}
|
|
midpoints[curr_midp].x = midpoint[0] / 3.0;
|
|
midpoints[curr_midp].y = midpoint[1] / 3.0;
|
|
midpoints[curr_midp].z = midpoint[2] / 3.0;
|
|
midpoints[curr_midp].oct = -1;
|
|
midpoints[curr_midp].elem = i;
|
|
curr_midp++;
|
|
}
|
|
|
|
bb[3] += 0.1;
|
|
|
|
bb[4] += 0.1;
|
|
|
|
bb[5] += 0.1;
|
|
|
|
TRY (H5t_set_bounding_box (m->octree, bb));
|
|
|
|
TRY (H5t_set_maxpoints (m->octree, max_num_elems_p_chunk/ h5tpriv_get_num_new_elems(m)));
|
|
|
|
TRY (H5t_refine_w_points(m->octree, midpoints, m->num_glb_elems[0], max_num_elems_p_chunk));
|
|
|
|
TRY (H5t_add_points_to_leaf (m->octree, midpoints, m->num_glb_elems[0]));
|
|
|
|
// set octree userlevel
|
|
h5t_oct_iterator_t* iter = NULL;
|
|
|
|
TRY (H5t_init_leafoct_iterator (m->octree, &iter));
|
|
|
|
h5_oct_idx_t oct_idx;
|
|
while ((oct_idx = H5t_iterate_oct (iter)) != -1) {
|
|
TRY (H5t_set_userlevel (m->octree, oct_idx, 0));
|
|
}
|
|
TRY (H5t_end_iterate_oct (iter));
|
|
|
|
TRY (H5t_update_internal (m->octree));
|
|
// reorder elements
|
|
// midpoints where already ordered according to octants (i.e. chunks)
|
|
|
|
h5_loc_idx_t size = m->num_interior_elems[m->leaf_level];
|
|
h5_loc_elem_t* loc_elems = m->loc_elems;
|
|
m->loc_elems = NULL;
|
|
TRY (h5tpriv_alloc_loc_elems (m, 0, size));
|
|
|
|
//TODO include ordering in subchunks
|
|
h5_loc_idx_t* loc_vertex_indices;
|
|
h5_loc_idx_t* old_loc_vertex_indices;
|
|
// could get a problem is no element is added
|
|
h5_chk_idx_t num_chunks = 1;
|
|
h5_oct_idx_t old_idx = midpoints[0].oct;
|
|
|
|
h5_weight_t* old_weights = m->weights;
|
|
TRY (m->weights = h5_calloc(m->num_weights * m->num_glb_elems[0], sizeof (* m->weights) ));
|
|
if (m->num_weights < 1) {
|
|
m->weights = NULL;
|
|
}
|
|
h5t_oct_count_list_t oct_c_list;
|
|
oct_c_list.num_items = 0;
|
|
oct_c_list.size = size;
|
|
TRY (oct_c_list.items = h5_calloc (size, sizeof (*oct_c_list.items)));
|
|
oct_c_list.items[oct_c_list.num_items++].oct = midpoints[0].oct;
|
|
int running_counter = 0;
|
|
// copy the elements into the right order
|
|
for (int i = 0; i < size; i++) {
|
|
if (midpoints[i].oct != old_idx) {
|
|
// this will be a new chunk
|
|
num_chunks++;
|
|
old_idx = midpoints[i].oct;
|
|
oct_c_list.items[oct_c_list.num_items].oct = old_idx;
|
|
oct_c_list.items[oct_c_list.num_items-1].count = i - running_counter;
|
|
running_counter = i;
|
|
oct_c_list.num_items++;
|
|
}
|
|
// permute weights
|
|
memcpy(&m->weights[i*m->num_weights],
|
|
&old_weights[midpoints[i].elem *m->num_weights],
|
|
sizeof (*m->weights) * m->num_weights);
|
|
|
|
loc_vertex_indices = h5tpriv_get_loc_elem_vertex_indices (m, i);
|
|
|
|
old_loc_vertex_indices = h5tpriv_get_loc_elem_vertex_indices_of_array (m, midpoints[i].elem, loc_elems);
|
|
|
|
h5tpriv_set_loc_elem_parent_idx (m, i, -1);
|
|
h5tpriv_set_loc_elem_child_idx (m, i, -1);
|
|
h5tpriv_set_loc_elem_level_idx (m, i, m->leaf_level);
|
|
|
|
memcpy (loc_vertex_indices, old_loc_vertex_indices, num_vertices * sizeof (*loc_vertex_indices));
|
|
|
|
/* add edges to map edges -> elements */
|
|
h5_loc_idx_t face_idx;
|
|
|
|
for (face_idx = 0; face_idx < num_faces; face_idx++) {
|
|
// add edges to neighbour struct
|
|
TRY (h5tpriv_enter_te2 (m, face_idx, i, NULL));
|
|
}
|
|
|
|
}
|
|
oct_c_list.items[oct_c_list.num_items-1].count = size - running_counter;
|
|
|
|
// free loc_elems
|
|
TRY (h5_free (loc_elems));
|
|
|
|
// free old_weights
|
|
TRY (h5_free (old_weights));
|
|
|
|
// set up chunk structure
|
|
TRY (h5tpriv_init_chunks (m));
|
|
|
|
TRY (h5tpriv_grow_chunks (m, num_chunks));
|
|
|
|
// create chunks
|
|
h5_glb_idx_t elem_range[2];
|
|
elem_range[0] = 0;
|
|
elem_range[1] = m->num_glb_elems[m->leaf_level];
|
|
h5_glb_idx_t chk_range[2];
|
|
chk_range[0] = 0;
|
|
chk_range[1] = num_chunks;
|
|
TRY (h5tpriv_store_chunks (m, &oct_c_list, num_chunks, elem_range, chk_range));
|
|
TRY (h5_free (oct_c_list.items));
|
|
|
|
h5t_oct_userdata_t* userdata = NULL;
|
|
//store userdata to chunks
|
|
for (int j = 0; j < num_chunks; j++) {
|
|
TRY (H5t_get_userdata_rw (m->octree, m->chunks->chunks[j].oct_idx,(void **) &userdata));
|
|
userdata->idx[0] = (h5_chk_idx_t) j;
|
|
}
|
|
|
|
TRY (H5t_update_userdata (m->octree));
|
|
TRY (h5_free (midpoints));
|
|
}
|
|
|
|
|
|
|
|
/* assign global indices to new indices */
|
|
TRY (assign_glb_elem_indices (m));
|
|
|
|
/* rebuild map: global index -> local_index */
|
|
TRY (rebuild_map_elem_g2l (m));
|
|
|
|
/* mesh specific finalize */
|
|
TRY (m->methods->store->end_store_elems (m));
|
|
|
|
|
|
#ifdef CHUNKING_OF_VTX
|
|
// abbandon chunking of vtx for time reasons
|
|
if (m->leaf_level == 0) {
|
|
// sort vertices
|
|
//calculate permutation
|
|
h5t_vtx_chk_list_t* permut = NULL;
|
|
TRY (permut = h5_calloc (m->num_loc_vertices[m->leaf_level], sizeof (*permut)));
|
|
memset (permut, -1,m->num_loc_vertices[m->leaf_level]*sizeof (*permut));
|
|
TRY (h5tpriv_calc_vtx_permutation (m, permut));
|
|
|
|
h5t_vtx_chk_list_t* rev_permut = NULL; // here is the reverse permutation
|
|
TRY (rev_permut = h5_calloc (m->num_loc_vertices[m->leaf_level], sizeof (*rev_permut)));
|
|
|
|
TRY (h5tpriv_calc_vtx_permutation (m, permut));
|
|
|
|
TRY (h5tpriv_calc_vtx_revpermutation (m, permut, rev_permut));
|
|
|
|
// permute vertices
|
|
h5_loc_vertex_t* vertices = m->vertices;
|
|
m->vertices = NULL;
|
|
TRY (h5tpriv_alloc_loc_vertices (m, *m->num_loc_vertices));
|
|
for (h5_loc_idx_t i = 0; i < *m->num_loc_vertices; i++) {
|
|
memcpy (&m->vertices[i], &vertices[permut[i].vtx], sizeof (*vertices));
|
|
}
|
|
TRY (h5_free (vertices));
|
|
TRY (assign_global_vertex_indices (m));
|
|
TRY (h5_free (m->map_vertex_g2l.items));
|
|
m->map_vertex_g2l.items = NULL;
|
|
size_t size = m->num_loc_vertices[m->leaf_level] + 128;
|
|
TRY (h5priv_new_idxmap (&m->map_vertex_g2l, size));
|
|
TRY (h5tpriv_rebuild_map_vertex_g2l (m, m->leaf_level, m->leaf_level));
|
|
m->last_stored_vid_before_ref = -1;
|
|
// update elements
|
|
|
|
// permute vertex_indices
|
|
for (h5_loc_idx_t i = 0; i < *m->num_glb_elems; i++) {
|
|
h5_loc_idx_t* vertex_indices = NULL;
|
|
int num_vtx = h5tpriv_ref_elem_get_num_vertices(m);
|
|
vertex_indices = h5tpriv_get_loc_elem_vertex_indices (m, i);
|
|
for (int j = 0; j < num_vtx; j++) {
|
|
vertex_indices[j] = rev_permut[vertex_indices[j]].vtx;
|
|
}
|
|
TRY (h5tpriv_sort_local_vertex_indices (m, vertex_indices, num_vtx));
|
|
|
|
// TODO is this necessary or already done with end store elems
|
|
/* add edges to map edges -> elements */
|
|
h5_loc_idx_t face_idx;
|
|
int num_faces = h5tpriv_ref_elem_get_num_edges (m);
|
|
for (face_idx = 0; face_idx < num_faces; face_idx++) {
|
|
// add edges to neighbour struct
|
|
TRY (h5tpriv_enter_te2 (m, face_idx, i, NULL));
|
|
}
|
|
|
|
}
|
|
// store vtx info to chunks
|
|
TRY (h5tpriv_store_vtx_range_to_chk (m, permut));
|
|
// /* mesh specific finalize */
|
|
// TRY (m->methods->store->end_store_elems (m));
|
|
}
|
|
#endif // CHUNKING_OF_VTX
|
|
|
|
#endif
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
#ifdef PARALLEL_IO
|
|
h5_err_t
|
|
h5tpriv_find_oct_proc_of_point (
|
|
h5t_mesh_t* m,
|
|
h5_loc_idx_t loc_idx,
|
|
h5_oct_point_t* point,
|
|
h5_int32_t* proc
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, loc_idx=%lld, point=%p, proc=%d", m, (long long int)loc_idx, point,*proc);
|
|
h5_loc_idx_t* indices = h5tpriv_get_loc_elem_vertex_indices (m, loc_idx);
|
|
h5_float64_t midpoint[3] = {0, 0, 0};
|
|
h5_float64_t P[3];
|
|
int num_vertices = h5tpriv_ref_elem_get_num_vertices (m);
|
|
|
|
for (int j = 0; j < num_vertices; j++) {
|
|
TRY (h5t_get_vertex_coords_by_index (m, indices[j], P));
|
|
midpoint[0] += P[0];
|
|
midpoint[1] += P[1];
|
|
midpoint[2] += P[2];
|
|
}
|
|
point->x = midpoint[0] / ((double) num_vertices);
|
|
point->y = midpoint[1] / ((double) num_vertices);
|
|
point->z = midpoint[2] / ((double) num_vertices);
|
|
|
|
point->elem = -1;
|
|
// check in which octant the new elems would be
|
|
TRY (point->oct = H5t_find_leafoctant_of_point (m->octree, 0, H5t_get_bounding_box (m->octree), point));
|
|
// get proc of octant
|
|
*proc = H5t_get_proc (m->octree, point->oct);
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
int compare_midpoint_oct (const void *p_a, const void *p_b) {
|
|
return ((h5_oct_point_t*) p_a)->oct - ((h5_oct_point_t*) p_b)->oct;
|
|
}
|
|
/*
|
|
* Update the marked_entities list such that it contains all elements that are
|
|
* going to be refined with the current proc
|
|
*/
|
|
h5_err_t
|
|
h5tpriv_mark_chk_elems_to_refine (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idxlist_t* glb_list,
|
|
h5_oct_point_t* midpoint_list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, glb_list=%p", m, glb_list);
|
|
// clear marked_entities list
|
|
TRY (h5priv_free_loc_idlist (&m->marked_entities));
|
|
TRY (h5priv_alloc_loc_idlist (&m->marked_entities, MAX_NUM_ELEMS_TO_REFINE_LOCALLY));
|
|
|
|
h5_glb_idx_t glb_idx = -1;
|
|
h5_loc_idx_t loc_idx = -1;
|
|
h5_oct_point_t point;
|
|
int counter = 0;
|
|
// go through all elems
|
|
for (int i = 0; i < glb_list->num_items; i++) {
|
|
glb_idx = glb_list->items[i];
|
|
|
|
// check if element is locally available (if not some other proc needs to refine it)
|
|
loc_idx = h5t_map_glb_elem_idx2loc(m, glb_idx);
|
|
if (loc_idx >= 0) {
|
|
// check in which octant the element is
|
|
h5_int32_t proc = -1;
|
|
TRY (h5tpriv_find_oct_proc_of_point (m, loc_idx, &point, &proc)); //TODO maybe use hash table here!!!
|
|
|
|
if (proc == m->f->myproc && // needs to be in my octant
|
|
h5priv_find_in_loc_idlist(m->marked_entities, loc_idx) < 0 && // not already in list
|
|
h5tpriv_get_loc_elem_child_idx (m, loc_idx) == -1) { // not refined already
|
|
// element is in octant of this proc, add to marked list
|
|
TRY (h5priv_search_in_loc_idlist (&m->marked_entities, loc_idx));
|
|
|
|
midpoint_list[counter].x = point.x;
|
|
midpoint_list[counter].y = point.y;
|
|
midpoint_list[counter].z = point.z;
|
|
midpoint_list[counter].oct = point.oct;
|
|
midpoint_list[counter].elem = h5tpriv_get_loc_elem_glb_idx(m, loc_idx);
|
|
counter++;
|
|
}
|
|
}
|
|
}
|
|
// sort midpoint list such that they are aligned according to octants
|
|
qsort (midpoint_list, counter, sizeof (*midpoint_list), compare_midpoint_oct);
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
#endif
|
|
/*
|
|
Mark entity for further processing (e.g. refinement).
|
|
*/
|
|
h5_err_t
|
|
h5t_mark_entity (
|
|
h5t_mesh_t* const m,
|
|
const h5_loc_id_t entity_id
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p, entity_id=%llu",
|
|
m, (long long unsigned)entity_id);
|
|
H5_CORE_API_RETURN (h5priv_insert_into_loc_idlist (&m->marked_entities, entity_id, -1));
|
|
}
|
|
|
|
h5_err_t
|
|
h5t_pre_refine (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
H5_CORE_API_RETURN (m->methods->store->pre_refine (m));
|
|
}
|
|
#ifdef PARALLEL_IO
|
|
//TODO maybe use ifdef to have name without _chk
|
|
h5_err_t
|
|
h5t_pre_refine_chk (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idxlist_t** glb_list,
|
|
h5_oct_point_t** point_list
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
// exchange list of marked entities
|
|
TRY (*point_list = h5_calloc (m->num_glb_leaf_elems[m->leaf_level-1], sizeof (**point_list))); // alloc for maximal num elems to refine
|
|
|
|
TRY (h5priv_exchange_loc_list_to_glb (m, glb_list));
|
|
h5_glb_idxlist_t* glb_marked_entities = *glb_list;
|
|
|
|
// decide which elements this proc has to refine
|
|
TRY (h5tpriv_mark_chk_elems_to_refine (m, glb_marked_entities, *point_list));
|
|
|
|
//TODO maybe check that sum of m->marked_entities->num_items over all proc is equal to glb_marked_entities->num_items
|
|
// this would find out if there is a problem with loading neighboring chunks...
|
|
|
|
H5_CORE_API_RETURN (m->methods->store->pre_refine (m));
|
|
}
|
|
#endif
|
|
/*
|
|
Refine previously marked elements.
|
|
*/
|
|
h5_err_t
|
|
h5t_refine_marked_elems (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
int i;
|
|
for (i = 0; i < m->marked_entities->num_items; i++) {
|
|
TRY (h5tpriv_refine_elem (m, m->marked_entities->items[i]));
|
|
}
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
#ifdef PARALLEL_IO
|
|
/*
|
|
* Calculate the global entity range
|
|
* range[i] = first glb entity of proc i
|
|
* range[nproc] = next idx to assign
|
|
*/
|
|
h5_err_t
|
|
h5tpriv_get_ranges (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idx_t* range,
|
|
h5_glb_idx_t mycount,
|
|
h5_glb_idx_t glb_start
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, range=%p, mycount=%lld, glb_start=%lld", m, range, (long long int) mycount, (long long int) glb_start);
|
|
|
|
TRY (h5priv_mpi_allgather (
|
|
&mycount,
|
|
1,
|
|
MPI_LONG,
|
|
&range[1],
|
|
1,
|
|
MPI_LONG,
|
|
m->f->props->comm));
|
|
|
|
range[0] = glb_start;
|
|
|
|
for (int i = 1; i <= m->f->nprocs; i++) {
|
|
range[i] += range[i-1];
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* Calculate the global element range for the new elements
|
|
* range[i] = first glb element of proc i
|
|
* range[nproc] = next idx to assign
|
|
*/
|
|
h5_err_t
|
|
h5tpriv_get_elem_ranges (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idx_t* range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, range=%p", m, range);
|
|
h5_glb_idx_t sendbuf = m->marked_entities->num_items * h5tpriv_get_num_new_elems (m);
|
|
TRY (h5priv_mpi_allgather (
|
|
&sendbuf,
|
|
1,
|
|
MPI_LONG,
|
|
&range[1],
|
|
1,
|
|
MPI_LONG,
|
|
m->f->props->comm));
|
|
|
|
range[0] = m->leaf_level > 0 ? m->num_glb_elems[m->leaf_level-1] : 0; // TODo check if correct
|
|
|
|
for (int i = 1; i <= m->f->nprocs; i++) {
|
|
range[i] += range[i-1];
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* Check if edge is on proc border. If yes also check that it hasn't been refined yet and the other proc
|
|
* is also refining his element.
|
|
*/
|
|
int
|
|
check_edge (
|
|
h5t_mesh_t* const m,
|
|
const h5_loc_idx_t face_idx,
|
|
const h5_loc_idx_t elem_idx,
|
|
h5_glb_idxlist_t* glb_elems
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_loc_idx_t,
|
|
"m=%p, face_idx=%lld, elem_idx=%lld, glb_elems=%p",
|
|
m, (long long)face_idx, (long long)elem_idx, glb_elems);
|
|
h5_loc_idlist_t* retval;
|
|
// get all elements sharing the given edge
|
|
TRY (h5tpriv_find_te2 (m, face_idx, elem_idx, &retval));
|
|
|
|
size_t i;
|
|
for (i = 0; i < retval->num_items; i++) {
|
|
// check weather the found element has been refined
|
|
h5_loc_id_t kids[2] = {-1,-1};
|
|
TRY (h5tpriv_get_loc_entity_children (m, retval->items[i], kids));
|
|
if (kids[0] >= 0) {
|
|
// element has been refined
|
|
H5_PRIV_FUNC_LEAVE (0);
|
|
}
|
|
h5_loc_id_t el_id1 = retval->items[i];
|
|
h5_chk_idx_t chk_idx1 = -1;
|
|
h5_loc_id_t el_id2 = h5tpriv_build_entity_id(
|
|
h5tpriv_ref_elem_get_entity_type(m, h5tpriv_ref_elem_get_dim (m) -1),
|
|
face_idx,
|
|
elem_idx );
|
|
h5_chk_idx_t chk_idx2 = -2;
|
|
TRY (h5tpriv_find_chk_of_elem (m, el_id1, &chk_idx1));
|
|
TRY (h5tpriv_find_chk_of_elem (m, el_id2, &chk_idx2));
|
|
if (chk_idx1 == chk_idx2) {
|
|
H5_PRIV_FUNC_LEAVE (0);
|
|
}
|
|
// // BUG this works depending on what is my_proc interior elems or interior_chunks
|
|
//// // check weather the found element is owned by the same proc
|
|
//// if (m->loc_elems[elem_idx].my_proc == m->loc_elems[retval->items[i]].my_proc) {
|
|
//// // element is on same proc
|
|
////
|
|
//// }
|
|
// // check if it is going to be refined
|
|
// if (h5priv_find_in_glb_idxlist(glb_elems, m->loc_elems[h5tpriv_get_elem_idx(retval->items[i])].glb_idx) < 0 ) {
|
|
// // element is not going to be refined
|
|
// H5_PRIV_FUNC_LEAVE (0);
|
|
// }
|
|
// // check if it is on this proc
|
|
// if (h5priv_find_in_loc_idlist(m->marked_entities, retval->items[i]) >= 0 ) {
|
|
// // element is on same proc
|
|
// H5_PRIV_FUNC_LEAVE (0);
|
|
// }
|
|
}
|
|
|
|
|
|
H5_PRIV_FUNC_RETURN (1);
|
|
}
|
|
h5_loc_idx_t
|
|
get_new_vtx_of_edge(
|
|
h5t_mesh_t* const m,
|
|
h5_loc_id_t loc_id
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, loc_id=%lld",
|
|
m, (long long int)loc_id);
|
|
|
|
h5_loc_id_t kids[2] = {-1,-1};
|
|
TRY (h5tpriv_get_loc_entity_children (m, loc_id, kids));
|
|
if (kids[0] >= 0) {
|
|
// element has been refined, return bisecting point
|
|
h5_loc_idx_t edge0[2], edge1[2];
|
|
TRY (h5t_get_loc_vertex_indices_of_edge (m, kids[0], edge0));
|
|
TRY (h5t_get_loc_vertex_indices_of_edge (m, kids[1], edge1));
|
|
if ((edge0[0] == edge1[0]) || (edge0[0] == edge1[1])) {
|
|
H5_PRIV_FUNC_LEAVE (edge0[0]);
|
|
} else {
|
|
H5_PRIV_FUNC_LEAVE (edge0[1]);
|
|
}
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_ERR_INTERNAL); //edge that should be refined in not refined
|
|
}
|
|
/*
|
|
* Go through elements and find boundary edges that were refined on this proc.
|
|
* we try to find edges that are shared with non-local elements (they could have
|
|
* been refined) or if one of the local elements was refined on a different proc
|
|
*/
|
|
h5_err_t
|
|
h5tpriv_find_boundary_edges ( // todo maybe put some part into another function...
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idxlist_t* glb_elems,
|
|
h5_edge_list_t* list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, glb_elems=%p, list=%p",
|
|
m, glb_elems, list);
|
|
// go through marked elements
|
|
h5_loc_idx_t elem_idx = -1;
|
|
for (int i = 0; i < m->marked_entities->num_items; i++) {
|
|
elem_idx = h5tpriv_get_elem_idx( m->marked_entities->items[i]);
|
|
int num_faces = h5tpriv_ref_elem_get_num_facets(m);
|
|
for (int j = 0; j < num_faces; j++) {
|
|
h5_loc_idlist_t* retval = NULL;
|
|
// get all elements sharing the given edge
|
|
TRY (h5tpriv_find_te2 (m, j, elem_idx, &retval));
|
|
|
|
// check if it is a border edge //TODO does not work yet since flags are not set properly but as long as we have all surounding elems it's not a problem -> i.e. tetrahedrals
|
|
if (retval->flags == H5_BORDER_ENTITY && 0) {
|
|
// add to edgelist
|
|
h5_glb_idx_t vertices[2];
|
|
h5t_get_glb_vertex_indices_of_entity (m, retval->items[0], vertices);
|
|
|
|
// we need to get the edge_id of elem_idx (other elems may not be refined
|
|
// and therefore can not return the splitting vertex
|
|
int l = 0;
|
|
for (; l < retval->num_items; l++) {
|
|
if (elem_idx == h5tpriv_get_elem_idx (retval->items[l])) {
|
|
break;
|
|
}
|
|
}
|
|
assert (l < retval->num_items);
|
|
h5_loc_idx_t loc_new_vtx = get_new_vtx_of_edge(m, retval->items[l]);
|
|
assert (loc_new_vtx > -1);
|
|
|
|
TRY (h5tpriv_add_edge_list (list ,vertices[0], vertices[1], loc_new_vtx, m->f->myproc));
|
|
continue;
|
|
}
|
|
// check if one of the neighbors (locally available) was refined on a different proc
|
|
for (int k = 0; k < retval->num_items; k++) {
|
|
h5_loc_idx_t neigh_idx = h5tpriv_get_elem_idx (retval->items[k]);
|
|
if (neigh_idx == elem_idx) {
|
|
continue;
|
|
}
|
|
h5_glb_idx_t neigh_glb_idx = h5tpriv_get_loc_elem_glb_idx(m, neigh_idx);
|
|
h5_loc_idx_t idx = h5priv_find_in_glb_idxlist(glb_elems, neigh_glb_idx);
|
|
if (idx < 0) {
|
|
// element has not been refined
|
|
continue;
|
|
} else {
|
|
// check if it was refined on this proc
|
|
int proc = -1;
|
|
h5_oct_point_t point;
|
|
TRY (h5tpriv_find_oct_proc_of_point (m, neigh_idx, &point, &proc));
|
|
if (m->f->myproc != proc) {
|
|
// element was refined on different proc
|
|
// add to edgelist
|
|
h5_glb_idx_t vertices[2];
|
|
h5t_get_glb_vertex_indices_of_entity (m, retval->items[k], vertices);
|
|
|
|
// we need to get the edge_id of elem_idx (other elems may not be refined
|
|
// and therefore can not return the splitting vertex
|
|
int l = 0;
|
|
for (; l < retval->num_items; l++) {
|
|
if (elem_idx == h5tpriv_get_elem_idx (retval->items[l])) {
|
|
break;
|
|
}
|
|
}
|
|
assert (l < retval->num_items);
|
|
h5_loc_idx_t loc_new_vtx = get_new_vtx_of_edge(m, retval->items[l]);
|
|
assert (loc_new_vtx > -1);
|
|
TRY (h5tpriv_add_edge_list (list ,vertices[0], vertices[1],loc_new_vtx, m->f->myproc));
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
// sort & uniquify
|
|
TRY (h5tpriv_sort_edge_list (list));
|
|
TRY (h5tpriv_uniquify_edge_list (list));
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* exchange boundary edges info
|
|
*/
|
|
h5_err_t
|
|
exchange_boundary_edge_list (
|
|
h5t_mesh_t* const m,
|
|
h5_edge_list_t* b_edges,
|
|
h5_edge_list_t* glb_b_edges
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m); // TODO
|
|
|
|
int* recvcounts = NULL;
|
|
TRY (recvcounts = h5_calloc (m->f->nprocs, sizeof (*recvcounts)));
|
|
int* recvdisp = NULL;
|
|
TRY (recvdisp = h5_calloc (m->f->nprocs + 1, sizeof (*recvdisp)));
|
|
TRY (h5priv_mpi_allgather (
|
|
&b_edges->num_items,
|
|
1,
|
|
MPI_INT,
|
|
recvcounts,
|
|
1,
|
|
MPI_INT,
|
|
m->f->props->comm));
|
|
int tot_num_b_edges = 0;
|
|
recvdisp[0] = 0;
|
|
for (int i = 0; i < m->f->nprocs; i++) {
|
|
tot_num_b_edges += recvcounts[i];
|
|
recvdisp[i+1] = recvcounts[i] + recvdisp[i];
|
|
}
|
|
if (tot_num_b_edges > 0) {
|
|
TRY (h5tpriv_grow_edge_list (glb_b_edges, tot_num_b_edges));
|
|
|
|
TRY (h5priv_mpi_allgatherv (
|
|
b_edges->items,
|
|
b_edges->num_items,
|
|
h5_dta_types.mpi_edge_list_elem,
|
|
glb_b_edges->items,
|
|
recvcounts,
|
|
recvdisp,
|
|
h5_dta_types.mpi_edge_list_elem,
|
|
m->f->props->comm));
|
|
|
|
glb_b_edges->num_items = tot_num_b_edges;
|
|
h5tpriv_sort_edge_list(glb_b_edges);
|
|
}
|
|
TRY (h5_free(recvcounts));
|
|
TRY (h5_free(recvdisp));
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
h5_err_t
|
|
set_exchanged_glb_idx (
|
|
h5t_mesh_t* const m,
|
|
h5_edge_list_t* list,
|
|
h5_edge_list_t* glb_list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m); // TODO
|
|
|
|
for (int i = 0; i < list->num_items; i++) {
|
|
if ( list->items[i].proc != m->f->myproc) {
|
|
h5_int32_t retval = h5tpriv_find_edge_list(glb_list,&list->items[i]);
|
|
assert (retval != glb_list->num_items);
|
|
m->vertices[list->items[i].new_vtx].idx = glb_list->items[retval].new_vtx;
|
|
}
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* find local edges in glb list and find out which proc sets glb_idx
|
|
*/
|
|
h5_err_t
|
|
find_edges_in_boundary_edge_list (
|
|
h5_edge_list_t* list,
|
|
h5_edge_list_t* glb_list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "list=%p, glb_list=%p", list, glb_list);
|
|
h5_int32_t idx = -1;
|
|
for (int i = 0; i < list->num_items; i++) {
|
|
h5t_edge_list_elem_t* retval = bsearch (&list->items[i], glb_list->items,glb_list->num_items, sizeof(*list->items), compare_edge_list_elem );
|
|
assert (retval != NULL); //all items in list are copied from glb_list so retval can't be NULL
|
|
|
|
idx =(int) (retval - glb_list->items);
|
|
// if there was another proc with lower rank that refined the same edge, the edge would lie at position idx - 1
|
|
// so we try to find lowest proc that has refined edge i
|
|
h5t_edge_list_elem_t edge;
|
|
edge.vtx1 = list->items[i].vtx1;
|
|
edge.vtx2 = list->items[i].vtx2;
|
|
edge.proc = 0;
|
|
while (idx > 0 &&
|
|
compare_edge_list_elem (&glb_list->items[idx-1], &edge) >= 0) {
|
|
idx--;
|
|
}
|
|
list->items[i].proc = glb_list->items[idx].proc;
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* set glb_idx of new vertex into edge list -> will be exchanged to other procs
|
|
*/
|
|
h5_err_t
|
|
set_glb_idx_edge_list (
|
|
h5t_mesh_t* m,
|
|
h5_edge_list_t* list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, list=%p",m ,list);
|
|
for (int i = 0; i < list->num_items; i++) {
|
|
if (list->items[i].proc == m->f->myproc) {
|
|
list->items[i].new_vtx = m->vertices[list->items[i].new_vtx].idx;
|
|
assert (list->items[i].new_vtx != -1);
|
|
}
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* at the moment either split weights equally to children or assign equal as parent
|
|
*/
|
|
static h5_err_t
|
|
update_weight_children (
|
|
h5t_mesh_t* m,
|
|
h5_weight_t* parent_weight,
|
|
h5_weight_t* children_weight) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p",m );
|
|
int num_new_elems = h5tpriv_get_num_new_elems (m);
|
|
|
|
if (UPDATE_WEIGHTS == 1) { // split
|
|
for (int j = 0; j < m->num_weights; j++) {
|
|
children_weight[j] = MAX (1, parent_weight[j]/num_new_elems);
|
|
}
|
|
|
|
}
|
|
if (UPDATE_WEIGHTS == 2) { // copy
|
|
for (int j = 0; j < m->num_weights; j++) {
|
|
children_weight[j] = parent_weight[j];
|
|
}
|
|
}
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* function to set weights after refinement automatically
|
|
*/
|
|
static h5_err_t
|
|
h5tpriv_set_local_weights (
|
|
h5t_mesh_t* m,
|
|
h5_glb_idx_t* range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, range=%p",m ,range);
|
|
|
|
for (h5_glb_idx_t idx = range[m->f->myproc]; idx < range[m->f->myproc + 1]; idx++) {
|
|
// get loc_idx of elem
|
|
h5_loc_idx_t loc_idx = h5t_map_glb_elem_idx2loc (m, idx);
|
|
assert (loc_idx >= 0);
|
|
h5_loc_idx_t parent_idx = h5tpriv_get_loc_elem_parent_idx (m, loc_idx);
|
|
h5_glb_idx_t parent_glb_idx = h5tpriv_get_loc_elem_glb_idx (m, parent_idx);
|
|
h5_weight_t* parent_weight = NULL;
|
|
h5_weight_t* children_weight = NULL;
|
|
parent_weight = &m->weights[parent_glb_idx * m->num_weights];
|
|
children_weight = &m->weights[idx * m->num_weights];
|
|
TRY (update_weight_children (m, parent_weight, children_weight));
|
|
}
|
|
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* function to update weights after refinement
|
|
*/
|
|
static h5_err_t
|
|
h5tpriv_exchange_weights (
|
|
h5t_mesh_t* m,
|
|
h5_glb_idx_t* range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, range=%p",m ,range);
|
|
|
|
int* recvcounts = h5_calloc (m->f->nprocs, sizeof (* recvcounts));
|
|
int* recvdisp = h5_calloc (m->f->nprocs, sizeof (* recvdisp));
|
|
|
|
for (int i = 0; i < m->f->nprocs; i++) {
|
|
recvdisp[i] = (int) range[i] * m->num_weights;
|
|
recvcounts[i] = (int) (range[i+1]- range[i]) * m->num_weights;
|
|
|
|
}
|
|
|
|
int sendcount = (range[m->f->myproc + 1] - range[m->f->myproc]) * m->num_weights;
|
|
h5_weight_t* sendbuf = h5_calloc (sendcount, sizeof (*sendbuf));
|
|
|
|
memcpy (sendbuf, &m->weights[range[m->f->myproc] * m->num_weights], sendcount * sizeof (*sendbuf));
|
|
|
|
TRY (h5priv_mpi_allgatherv (
|
|
sendbuf,
|
|
sendcount,
|
|
MPI_INT,
|
|
m->weights,
|
|
recvcounts,
|
|
recvdisp,
|
|
MPI_INT,
|
|
m->f->props->comm));
|
|
for (h5_glb_idx_t i = 0; i < range[m->f->nprocs] * m->num_weights; i++ ) {
|
|
assert (m->weights[i] > 0);
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
Refine previously marked elements.
|
|
*/
|
|
h5_err_t
|
|
h5t_refine_marked_elems_chk (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idxlist_t* glb_elems,
|
|
h5_oct_point_t* midpoints
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
int num_midpoints = m->marked_entities->num_items;
|
|
|
|
// refine octree
|
|
TRY (H5t_refine_w_points (m->octree, midpoints, num_midpoints, H5t_get_maxpoints (m->octree)));
|
|
|
|
// sort midpoint list such that they are aligned according to octants
|
|
qsort (midpoints, num_midpoints, sizeof (*midpoints), compare_midpoint_oct);
|
|
|
|
// set octree userlevel
|
|
h5t_oct_iterator_t* iter = NULL;
|
|
|
|
TRY (H5t_init_leafoct_iterator (m->octree, &iter));
|
|
|
|
h5_oct_idx_t oct_idx;
|
|
while ((oct_idx = H5t_iterate_oct (iter)) != -1) {
|
|
if (H5t_get_proc (m->octree, oct_idx) == m->f->myproc) {
|
|
TRY (H5t_set_userlevel (m->octree, oct_idx, m->leaf_level));
|
|
}
|
|
}
|
|
TRY (H5t_end_iterate_oct (iter));
|
|
TRY (H5t_update_internal (m->octree));
|
|
|
|
// get elem ranges
|
|
h5_glb_idx_t* elem_range = NULL;
|
|
TRY (elem_range = h5_calloc (m->f->nprocs + 1, sizeof (*elem_range)));
|
|
|
|
//TODO use generic get_range function
|
|
TRY (h5tpriv_get_elem_ranges (m, elem_range));
|
|
|
|
// CHUNKS
|
|
h5_chk_idx_t num_chunks = 1;
|
|
|
|
h5t_oct_count_list_t oct_c_list; // list has contains all octants and number of elems per octant
|
|
oct_c_list.num_items = 0;
|
|
oct_c_list.size = num_midpoints;
|
|
TRY (oct_c_list.items = h5_calloc (num_midpoints, sizeof (*oct_c_list.items)));
|
|
|
|
h5_oct_idx_t old_idx = -1;
|
|
if (num_midpoints > 0) {
|
|
old_idx = midpoints[0].oct;
|
|
oct_c_list.items[oct_c_list.num_items++].oct = old_idx;
|
|
} else {
|
|
num_chunks = 0;
|
|
}
|
|
|
|
|
|
int running_counter = 0;
|
|
// calc number of chunks
|
|
for (int i = 0; i < num_midpoints; i++) {
|
|
if (midpoints[i].oct != old_idx) {
|
|
// point i will be in a new chunk
|
|
num_chunks++;
|
|
old_idx = midpoints[i].oct;
|
|
oct_c_list.items[oct_c_list.num_items].oct = old_idx;
|
|
oct_c_list.items[oct_c_list.num_items-1].count = i - running_counter;
|
|
running_counter = i;
|
|
oct_c_list.num_items++;
|
|
}
|
|
}
|
|
oct_c_list.items[oct_c_list.num_items-1].count = num_midpoints - running_counter;
|
|
// calc chunk range
|
|
h5_glb_idx_t* chk_range = NULL;
|
|
TRY (chk_range = h5_calloc (m->f->nprocs + 1, sizeof (*chk_range)));
|
|
TRY (h5tpriv_get_ranges (m, chk_range, num_chunks, m->chunks->curr_idx + 1));
|
|
|
|
// get total number of chunks
|
|
int tot_num_chunks = 0;
|
|
|
|
tot_num_chunks = chk_range[m->f->nprocs] - chk_range[0];
|
|
// alloc mem for chunks
|
|
TRY (h5tpriv_grow_chunks (m, tot_num_chunks));
|
|
|
|
// create chunks
|
|
TRY (h5tpriv_store_chunks (m, &oct_c_list, num_chunks, elem_range, chk_range));
|
|
|
|
// update newly created chunks
|
|
TRY (h5tpriv_update_chunks (m, chk_range));
|
|
|
|
h5t_oct_userdata_t* userdata = NULL;
|
|
//store userdata to octree
|
|
for (int j = chk_range[m->f->myproc]; j < chk_range[m->f->myproc + 1]; j++) {
|
|
assert ( H5t_get_proc (m->octree, m->chunks->chunks[j].oct_idx) == m->f->myproc);
|
|
TRY (H5t_get_userdata_rw (m->octree, m->chunks->chunks[j].oct_idx,(void **) &userdata));
|
|
if (userdata->idx[0] == -1) {
|
|
userdata->idx[0] = (h5_chk_idx_t) j;
|
|
} else if (userdata->idx[1] == -1) {
|
|
userdata->idx[1] = (h5_chk_idx_t) j;
|
|
} else if (userdata->idx[2] == -1) {
|
|
userdata->idx[2] = (h5_chk_idx_t) j;
|
|
} else if (userdata->idx[3] == -1) {
|
|
userdata->idx[3] = (h5_chk_idx_t) j;
|
|
} else {
|
|
H5_CORE_API_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
}
|
|
|
|
TRY (H5t_update_userdata (m->octree));
|
|
|
|
|
|
// refine elements
|
|
for (int i = 0; i < num_midpoints; i++) {
|
|
TRY (h5tpriv_refine_elem (m, h5t_map_glb_elem_idx2loc(m,midpoints[i].elem))); // needs to be ordered acc to octants
|
|
}
|
|
TRY (h5_free (oct_c_list.items));
|
|
TRY (h5_free (elem_range));
|
|
TRY (h5_free (chk_range));
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
/*
|
|
* This function checks if there is the possibility to add another chunk to an octant
|
|
*/
|
|
int
|
|
h5tpriv_octant_is_full (
|
|
h5t_octree_t* octree,
|
|
h5_oct_idx_t oct_idx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "octree=%p, oct_idx=%d", octree, oct_idx);
|
|
h5t_oct_userdata_t* userdata = NULL;
|
|
TRY (H5t_get_userdata_r (octree, oct_idx,(void **) &userdata));
|
|
if (userdata->idx[3] == -1) {
|
|
H5_PRIV_FUNC_LEAVE (0)
|
|
}
|
|
H5_PRIV_FUNC_RETURN (1);
|
|
}
|
|
|
|
/*
|
|
* only compares the glb_idx of a vertex
|
|
*/
|
|
int compare_glb_vertex (const void *p_a, const void *p_b) {
|
|
return ((h5_glb_vertex_t*) p_a)->idx - ((h5_glb_vertex_t*) p_b)->idx;
|
|
}
|
|
/*
|
|
* find vertex in list and return num_vtx if not in list
|
|
* list needs to be sorted
|
|
*/
|
|
static int
|
|
h5tpriv_find_vertex_in_list (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idx_t vtx_idx,
|
|
h5_glb_vertex_t* vtx_list,
|
|
int num_vtx
|
|
) {
|
|
h5_glb_vertex_t key;
|
|
key.idx = vtx_idx;
|
|
|
|
h5_glb_vertex_t* retval = bsearch (&key, vtx_list, num_vtx, sizeof (*retval), compare_glb_vertex);
|
|
if (retval == NULL) {
|
|
return num_vtx;
|
|
}
|
|
return retval - vtx_list;
|
|
}
|
|
static h5_err_t
|
|
h5tpriv_sort_vertex_list (
|
|
h5_glb_vertex_t* vtx_list,
|
|
int num_vtx
|
|
) {
|
|
qsort (vtx_list, num_vtx, sizeof(*vtx_list), compare_glb_vertex);
|
|
return (H5_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
int comp_vtx_coord (void* p_a, void* p_b) {
|
|
h5_glb_vertex_t* a = (h5_glb_vertex_t*)p_a;
|
|
h5_glb_vertex_t* b = (h5_glb_vertex_t*)p_b;
|
|
|
|
if (a->idx != b->idx) {
|
|
return a->idx != b->idx;
|
|
} else {
|
|
if (a->P[0] != b->P[0]) {
|
|
return a->P[0] != b->P[0];
|
|
} else {
|
|
if (a->P[1] != b->P[1]) {
|
|
return a->P[1] != b->P[1];
|
|
} else {
|
|
if (a->P[2] != b->P[2]) {
|
|
return a->P[2] != b->P[2];
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static h5_err_t
|
|
h5tpriv_add_glb_vertex_to_list (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idx_t vtx_idx,
|
|
h5_glb_vertex_t* glb_vtx,
|
|
h5_glb_idx_t num_glb_vtx,
|
|
h5_glb_vertex_t* vtx_list,
|
|
int* num_vtx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
h5_loc_idx_t loc_idx = h5tpriv_find_vertex_in_list (m, vtx_idx, glb_vtx, num_glb_vtx);
|
|
assert (loc_idx > -1 );
|
|
assert (loc_idx < num_glb_vtx);
|
|
memcpy (&vtx_list[*num_vtx], &glb_vtx[loc_idx], sizeof (*vtx_list));
|
|
(*num_vtx)++;
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
|
|
static h5_err_t
|
|
h5tpriv_init_glb_vtx_struct_chk (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_elem_t* glb_elems,
|
|
int num_glb_elems,
|
|
h5_glb_vertex_t* vtx_list,
|
|
int* num_vtx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
// todo could be optimised by using a hashtab for glb_idx_list instead of map
|
|
int num_vertices = h5tpriv_ref_elem_get_num_vertices(m);
|
|
|
|
h5_idxmap_t map_s;
|
|
TRY (h5priv_new_idxmap (&map_s, num_vertices * num_glb_elems));
|
|
h5_idxmap_t* map = &map_s;
|
|
|
|
h5_hashtable_t htab;
|
|
TRY (h5priv_hcreate (((num_vertices * num_glb_elems) << 2) / 3, &htab,
|
|
hidxmap_cmp, hidxmap_compute_hval, NULL));
|
|
|
|
for (int i = 0; i < num_glb_elems; i++) {
|
|
h5_glb_idx_t* vtx_idx = h5tpriv_get_glb_elem_vertices(m, glb_elems, i);
|
|
|
|
for (int j = 0; j < num_vertices; j++) {
|
|
// add index temporarly to map ...
|
|
map->items[map->num_items] = (h5_idxmap_el_t) {vtx_idx[j], 0};
|
|
// ... and check whether it has already been added
|
|
h5_idxmap_el_t* retval;
|
|
h5priv_hsearch (&map->items[map->num_items],
|
|
H5_ENTER, (void**)&retval, &htab);
|
|
|
|
if (retval == &map->items[map->num_items]) { // not in list
|
|
// new entry in hash table thus in map
|
|
map->num_items++;
|
|
//todo optimise by copy in the end (copy consequtive vtx together)
|
|
h5_loc_idx_t loc_idx = h5t_map_global_vertex_idx2local (m, vtx_idx[j]);
|
|
assert (loc_idx > -1 && loc_idx <= m->last_stored_vid);
|
|
memcpy (&vtx_list[*num_vtx], &m->vertices[loc_idx], sizeof (*vtx_list));
|
|
(*num_vtx)++;
|
|
}
|
|
}
|
|
}
|
|
TRY (h5priv_hdestroy (&htab));
|
|
TRY (h5_free (map->items));
|
|
TRY (h5tpriv_sort_vertex_list (vtx_list, *num_vtx));
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
// little bit different funtion since it's used to store and not to load...
|
|
static h5_err_t
|
|
h5tpriv_init_glb_vtx_struct_chk2 (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_elem_t* glb_elems,
|
|
int num_glb_elems,
|
|
h5_glb_vertex_t* glb_vtx,
|
|
int num_glb_vtx,
|
|
h5_glb_vertex_t* vtx_list,
|
|
int* num_vtx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
// todo could be optimised by using a hashtab for glb_idx_list instead of map
|
|
int num_vertices = h5tpriv_ref_elem_get_num_vertices(m);
|
|
h5_idxmap_t* map = &m->map_vertex_g2l;
|
|
if (map->size <= map->num_items) {
|
|
h5priv_grow_idxmap (map, map->size +10); // 1 should be enough
|
|
}
|
|
|
|
|
|
h5_hashtable_t htab;
|
|
TRY (h5priv_hcreate (((num_vertices * num_glb_elems) << 2) / 3, &htab,
|
|
hidxmap_cmp, hidxmap_compute_hval, NULL));
|
|
|
|
for (int i = 0; i < num_glb_elems; i++) {
|
|
h5_glb_idx_t* vtx_idx = h5tpriv_get_glb_elem_vertices(m, glb_elems, i);
|
|
|
|
for (int j = 0; j < num_vertices; j++) {
|
|
// add index temporarly to map ...
|
|
map->items[map->num_items] = (h5_idxmap_el_t) {vtx_idx[j], 0};
|
|
// ... and check whether it has already been added
|
|
h5_idxmap_el_t* retval;
|
|
h5priv_hsearch (&map->items[map->num_items],
|
|
H5_ENTER, (void**)&retval, &htab);
|
|
|
|
if (retval == &map->items[map->num_items]) { // not in list
|
|
// new entry in hash table
|
|
h5tpriv_add_glb_vertex_to_list(m, vtx_idx[j], glb_vtx, num_glb_vtx, vtx_list, num_vtx);
|
|
|
|
}
|
|
}
|
|
}
|
|
TRY (h5priv_hdestroy (&htab));
|
|
TRY (h5tpriv_sort_vertex_list (vtx_list, *num_vtx));
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* there are already all local & neighbor chunks in the list
|
|
* we remove all chunks that are not on m->leaf_level, and
|
|
* from neighbors
|
|
*/
|
|
|
|
static h5_err_t
|
|
get_list_of_chunks_to_retrieve (
|
|
h5t_mesh_t* const m,
|
|
h5_chk_idx_t* list,
|
|
int* num_list
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
// retrieve only chunks from this level
|
|
int tmp_counter = 0;
|
|
for (int i = 0; i < *num_list; i++) {
|
|
if (list[i] > m->chunks->curr_idx - m->chunks->num_chunks_p_level[m->leaf_level] && // only the chunks stored on the last level
|
|
H5t_get_proc (m->octree, m->chunks->chunks[list[i]].oct_idx) != m->f->myproc) {
|
|
list[tmp_counter] = list[i];
|
|
tmp_counter++;
|
|
}
|
|
}
|
|
*num_list = tmp_counter;
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
static h5_err_t
|
|
exchange_glb_elem_glb_vtx (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_elem_t* glb_elems,
|
|
int num_glb_elems,
|
|
h5_glb_elem_t** tot_glb_elems,
|
|
int* num_tot_glb_elems,
|
|
h5_glb_vertex_t* glb_vtx,
|
|
int num_glb_vtx,
|
|
h5_glb_vertex_t** tot_glb_vtx,
|
|
int* num_tot_glb_vtx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
h5_glb_idx_t* e_range = h5_calloc (m->f->nprocs +1, sizeof (*e_range));
|
|
TRY (h5tpriv_get_ranges(m, e_range, (h5_glb_idx_t) num_glb_elems, 0));
|
|
|
|
h5_glb_idx_t* v_range = h5_calloc (m->f->nprocs +1, sizeof (*v_range));
|
|
TRY (h5tpriv_get_ranges(m, v_range, (h5_glb_idx_t) num_glb_vtx, 0));
|
|
|
|
int* e_recvcounts = h5_calloc (m->f->nprocs, sizeof (* e_recvcounts));
|
|
int* v_recvcounts = h5_calloc (m->f->nprocs, sizeof (* v_recvcounts));
|
|
|
|
int* e_recvdisp = h5_calloc (m->f->nprocs, sizeof (* e_recvdisp));
|
|
int* v_recvdisp = h5_calloc (m->f->nprocs, sizeof (* v_recvdisp));
|
|
|
|
for (int i = 0; i < m->f->nprocs; i++) {
|
|
e_recvdisp[i] = (int) e_range[i];
|
|
v_recvdisp[i] = (int) v_range[i];
|
|
e_recvcounts[i] = (int) (e_range[i+1]- e_range[i]);
|
|
v_recvcounts[i] = (int) (v_range[i+1]- v_range[i]);
|
|
}
|
|
*num_tot_glb_elems = e_range[m->f->nprocs];
|
|
TRY (*tot_glb_elems = h5tpriv_alloc_glb_elems(m, *num_tot_glb_elems));
|
|
|
|
*num_tot_glb_vtx = v_range[m->f->nprocs];
|
|
*tot_glb_vtx = h5_calloc (*num_tot_glb_vtx, sizeof (**tot_glb_vtx));
|
|
|
|
|
|
TRY (h5priv_mpi_allgatherv (
|
|
glb_elems,
|
|
num_glb_elems,
|
|
h5tpriv_get_mpi_type_of_glb_elem(m),
|
|
*tot_glb_elems,
|
|
e_recvcounts,
|
|
e_recvdisp,
|
|
h5tpriv_get_mpi_type_of_glb_elem(m),
|
|
m->f->props->comm));
|
|
|
|
TRY (h5priv_mpi_allgatherv (
|
|
glb_vtx,
|
|
num_glb_vtx,
|
|
h5_dta_types.mpi_glb_vtx,
|
|
*tot_glb_vtx,
|
|
v_recvcounts,
|
|
v_recvdisp,
|
|
h5_dta_types.mpi_glb_vtx,
|
|
m->f->props->comm));
|
|
|
|
TRY (h5tpriv_sort_vertex_list (*tot_glb_vtx, *num_tot_glb_vtx));
|
|
TRY (h5tpriv_sort_glb_elems (m, *tot_glb_elems, (size_t)*num_tot_glb_elems));
|
|
|
|
// free mem
|
|
TRY (h5_free (e_recvcounts));
|
|
TRY (h5_free (v_recvcounts));
|
|
TRY (h5_free (e_recvdisp));
|
|
TRY (h5_free (v_recvdisp));
|
|
TRY (h5_free (e_range));
|
|
TRY (h5_free (v_range));
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
* compare chk_idx
|
|
*/
|
|
int compare_chk_list(const void *p_a, const void *p_b) {
|
|
return ((h5t_chunk_t*) p_a)->idx - ((h5t_chunk_t*) p_b)->idx;
|
|
}
|
|
|
|
h5_err_t
|
|
store_exchanged_elems (
|
|
h5t_mesh_t* const m,
|
|
h5_chk_idx_t* chk_list,
|
|
int num_chk_list,
|
|
h5_glb_elem_t* glb_elems,
|
|
int num_glb_elems,
|
|
h5_glb_vertex_t* glb_vtx,
|
|
int num_glb_vtx
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
qsort (chk_list, num_chk_list, sizeof (*chk_list), compare_chk_list);
|
|
|
|
// calc how many new elems
|
|
int num_new_elems = 0;
|
|
for (int i = 0; i < num_chk_list; i++) {
|
|
num_new_elems += m->chunks->chunks[chk_list[i]].num_elems;
|
|
}
|
|
TRY (h5tpriv_alloc_loc_elems (m, m->num_interior_elems[m->leaf_level], m->num_interior_elems[m->leaf_level] + num_new_elems));
|
|
|
|
// extract glb elems that should be stored
|
|
h5_glb_elem_t* new_elems = NULL;
|
|
h5_loc_idx_t new_elems_c = 0; // counter
|
|
|
|
// temporary idx list so we don't have to search in glb_elems. glb_elems should be sorted!
|
|
h5_glb_idxlist_t* glb_list = NULL;
|
|
h5priv_alloc_glb_idxlist (&glb_list, num_glb_elems);
|
|
for (int i = 0; i < num_glb_elems; i++) {
|
|
glb_list->items[i] = h5tpriv_get_glb_elem_idx (m, glb_elems, i);
|
|
}
|
|
glb_list->num_items = num_glb_elems;
|
|
|
|
int* proc = h5_calloc (num_new_elems, sizeof (*proc));
|
|
int proc_counter = 0;
|
|
TRY (new_elems = h5tpriv_alloc_glb_elems(m, num_new_elems));
|
|
for (int i = 0; i < num_chk_list; i++) {
|
|
int num_elems = m->chunks->chunks[chk_list[i]].num_elems;
|
|
int chk_proc = H5t_get_proc (m->octree, m->chunks->chunks[chk_list[i]].oct_idx );
|
|
|
|
h5_glb_idx_t glb_idx = m->chunks->chunks[chk_list[i]].elem;
|
|
h5_loc_idx_t loc_idx = h5priv_find_in_glb_idxlist (glb_list, glb_idx);
|
|
assert (loc_idx > -1);
|
|
assert (h5tpriv_get_glb_elem_idx (m,glb_elems, loc_idx) == glb_idx);
|
|
|
|
TRY(h5tpriv_copy_glb_elems(m, new_elems, new_elems_c, glb_elems, loc_idx, num_elems));
|
|
new_elems_c += num_elems;
|
|
while (proc_counter < new_elems_c) {
|
|
|
|
proc[proc_counter] = chk_proc; // TODO may need to be changed after we have lb
|
|
proc_counter++;
|
|
}
|
|
}
|
|
assert (new_elems_c == num_new_elems);
|
|
|
|
|
|
// create list of new glb_vtx
|
|
h5_glb_vertex_t* new_vtx = h5_calloc(new_elems_c * 4, sizeof (*new_vtx));// TODO should be by far enough -> could be optimzed
|
|
int new_vtx_c = 0;
|
|
|
|
|
|
// TODO maybe this function could be extended and used instead of the stuff below
|
|
//TRY (h5tpriv_init_glb_vtx_struct_chk (m, new_elems, new_elems_c, new_vtx, &new_vtx_c));
|
|
// extract glb vertices that should be stored
|
|
TRY (h5tpriv_init_glb_vtx_struct_chk2 (m, new_elems, new_elems_c,
|
|
glb_vtx, num_glb_vtx, new_vtx, &new_vtx_c));
|
|
// int num_vertices = h5tpriv_ref_elem_get_num_vertices(m);
|
|
// for (int i = 0; i < new_elems_c; i++) {
|
|
// h5_glb_idx_t* vertices = h5tpriv_get_glb_elem_vertices(m, new_elems, i);
|
|
// for (int j = 0; j < num_vertices; j++) {
|
|
// // check if vertex is already locally available
|
|
// int idx = -1;
|
|
// TRY (idx = h5tpriv_find_glb_idx_in_map (&m->map_vertex_g2l, vertices[j]));
|
|
// if (idx == m->map_vertex_g2l.num_items) { // locally not available
|
|
// // add at end and sort later
|
|
// h5tpriv_add_glb_vertex_to_list(m, vertices[j], glb_vtx, num_glb_vtx, new_vtx, &new_vtx_c);
|
|
// }
|
|
// }
|
|
// }
|
|
// TRY (h5tpriv_sort_vertex_list (new_vtx, new_vtx_c));
|
|
|
|
// store vertices
|
|
|
|
TRY (h5tpriv_alloc_loc_vertices (m, new_vtx_c + m->last_stored_vid + 1)); // maybe somewhat more?
|
|
memcpy (&m->vertices[m->last_stored_vid + 1], new_vtx, new_vtx_c * sizeof (*new_vtx));
|
|
m->last_stored_vid += new_vtx_c;
|
|
|
|
// rebuild map vtx
|
|
TRY (h5priv_grow_idxmap (&m->map_vertex_g2l, new_vtx_c + m->map_vertex_g2l.size));
|
|
TRY (h5tpriv_rebuild_map_vertex_g2l_partial (m));
|
|
|
|
|
|
// store elems
|
|
TRY (h5priv_grow_idxmap (&m->map_elem_g2l, num_new_elems + m->map_elem_g2l.size));
|
|
TRY (h5tpriv_init_loc_elems_struct (m, new_elems, m->num_interior_elems[m->leaf_level], num_new_elems, 0, proc));
|
|
|
|
// rebuild map elems
|
|
TRY (rebuild_map_elem_g2l_partial (m));
|
|
|
|
TRY (h5tpriv_init_elem_flags (m, m->num_interior_elems[m->leaf_level], num_new_elems));
|
|
|
|
m->num_interior_elems[m->leaf_level] += num_new_elems;
|
|
|
|
TRY (h5_free (new_elems));
|
|
TRY (h5_free (new_vtx));
|
|
TRY (h5_free (proc));
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
#endif
|
|
|
|
h5_err_t
|
|
h5t_post_refine (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
TRY (h5t_end_store_vertices (m));
|
|
TRY (h5t_end_store_elems (m));
|
|
H5_CORE_API_RETURN (h5priv_free_loc_idlist (&m->marked_entities));
|
|
}
|
|
|
|
|
|
#ifdef PARALLEL_IO
|
|
|
|
h5_err_t
|
|
h5t_post_refine_chk (
|
|
h5t_mesh_t* const m,
|
|
h5_glb_idxlist_t* marked_glb_elems
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
h5_debug("post_refine_chk");
|
|
// get boundary edges
|
|
h5_edge_list_t* b_edges = h5tpriv_init_edge_list(h5tpriv_ref_elem_get_num_edges(m) * m->marked_entities->num_items);
|
|
TRY (h5tpriv_find_boundary_edges (m, marked_glb_elems, b_edges));
|
|
|
|
// exchange boundary edges
|
|
h5_edge_list_t* glb_b_edges = h5tpriv_init_edge_list(0);
|
|
TRY (exchange_boundary_edge_list (m, b_edges, glb_b_edges));
|
|
|
|
// find out which edges are split by other procs (i.e. with lower rank)
|
|
// set proc in b_edges to proc who sets glb_idx
|
|
TRY (find_edges_in_boundary_edge_list (b_edges, glb_b_edges));
|
|
|
|
|
|
// calc vertex range, num loc vertices = (num new vertices - vertices to be set by other proc)
|
|
int num_vtx_not_named = 0;
|
|
for (int i = 0; i < b_edges->num_items; i++) {
|
|
b_edges->items[i].proc != m->f->myproc ? num_vtx_not_named++ : 0;
|
|
}
|
|
h5_glb_idx_t* vtx_range = NULL;
|
|
TRY (vtx_range = h5_calloc (m->f->nprocs + 1, sizeof (*vtx_range)));
|
|
TRY (h5tpriv_get_ranges(m, vtx_range, m->last_stored_vid - m->last_stored_vid_before_ref - num_vtx_not_named, m->num_glb_vertices[m->leaf_level-1]));
|
|
|
|
// assign glb vtx idx
|
|
m->num_loc_vertices[m->leaf_level] = m->last_stored_vid+1;
|
|
|
|
// make list of loc vtx that don't get a glb_idx from this proc
|
|
h5_loc_idxlist_t* vtx_list = NULL;
|
|
TRY (h5priv_alloc_loc_idxlist(&vtx_list, b_edges->num_items));
|
|
for (int i = 0; i < b_edges->num_items; i++) {
|
|
if (b_edges->items[i].proc != m->f->myproc) {
|
|
TRY (h5priv_search_in_loc_idxlist (&vtx_list, (h5_loc_idx_t)b_edges->items[i].new_vtx));
|
|
}
|
|
}
|
|
|
|
TRY (assign_global_vertex_indices_chk (m, vtx_list, vtx_range));
|
|
|
|
// set glb_idx in b_edge list
|
|
TRY (set_glb_idx_edge_list (m, b_edges));
|
|
|
|
// exchange glb_idx of vertices
|
|
TRY (exchange_boundary_edge_list (m, b_edges, glb_b_edges));
|
|
// TODO could be more efficient by only sending the glb_idx around entries around
|
|
// but one would need to create a new list...
|
|
|
|
// set exchanged glb_idx
|
|
TRY (set_exchanged_glb_idx (m, b_edges, glb_b_edges));
|
|
|
|
// rebuild map g2l
|
|
TRY (h5priv_grow_idxmap (&m->map_vertex_g2l, m->map_vertex_g2l.num_items + m->last_stored_vid - m->last_stored_vid_before_ref));
|
|
TRY (h5tpriv_rebuild_map_vertex_g2l_partial (m));
|
|
m->last_stored_vid_before_ref = m->last_stored_vid;
|
|
// this is replacing TRY (h5t_end_store_vertices (m));
|
|
// since we need a special assign glb_idx
|
|
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
|
|
// get elem ranges
|
|
h5_glb_idx_t* elem_range = NULL;
|
|
TRY (elem_range = h5_calloc (m->f->nprocs + 1, sizeof (*elem_range)));
|
|
|
|
//TODO use generic get_range function
|
|
TRY (h5tpriv_get_elem_ranges (m, elem_range));
|
|
|
|
m->num_interior_elems[m->leaf_level] = m->last_stored_eid+1; // TODO needs to be reset after exchange
|
|
m->num_glb_elems[m->leaf_level] = elem_range[m->f->nprocs];
|
|
m->num_glb_leaf_elems[m->leaf_level] = m->num_glb_leaf_elems[m->leaf_level - 1] +
|
|
(h5tpriv_get_num_new_elems(m) - 1) * (m->num_glb_elems[m->leaf_level]- m->num_glb_elems[m->leaf_level-1]);
|
|
// idea: after ref we have the same number of leaf elems + all refined elems - elems that were refined
|
|
|
|
/* assign global indices to new indices */
|
|
TRY (assign_glb_elem_indices_chk (m, elem_range));
|
|
|
|
|
|
/* rebuild map: global index -> local_index */
|
|
TRY (rebuild_map_elem_g2l_partial (m));
|
|
m->last_stored_eid_before_ref = m->last_stored_eid;
|
|
|
|
|
|
// weights
|
|
h5_debug("weights");
|
|
if (m->num_weights < 1) {
|
|
m->weights = NULL;
|
|
} else {
|
|
TRY ( m->weights = h5_alloc (m->weights, elem_range[m->f->nprocs] * m->num_weights * sizeof (*m->weights)));
|
|
|
|
// set local weights
|
|
TRY (h5tpriv_set_local_weights (m, elem_range));
|
|
|
|
// exchange weights
|
|
TRY (h5tpriv_exchange_weights (m, elem_range));
|
|
}
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
// get list of new chunks
|
|
h5_chk_idx_t* chk_send_list = NULL;
|
|
int counter = 0;
|
|
TRY (h5tpriv_get_list_of_chunks_to_write (m, &chk_send_list, &counter));
|
|
|
|
// send only chunks from this level
|
|
int tmp_counter = 0;
|
|
for (int i = 0; i < counter; i++) {
|
|
if (chk_send_list[i] > m->chunks->curr_idx - m->chunks->num_chunks_p_level[m->leaf_level]) { // only the chunks stored on the last level
|
|
chk_send_list[tmp_counter] = chk_send_list[i];
|
|
tmp_counter++;
|
|
}
|
|
}
|
|
// TODO this should be optimized only really needed chunks should be sent around
|
|
|
|
counter = tmp_counter;
|
|
// create glb_chunks
|
|
h5_glb_elem_t* glb_elems = NULL;
|
|
int num_glb_elems = m->num_interior_elems[m->leaf_level] - m->num_interior_elems[m->leaf_level-1];
|
|
TRY (glb_elems = h5tpriv_alloc_glb_elems(m, num_glb_elems));
|
|
TRY (h5tpriv_init_glb_elems_struct_chk(m, glb_elems, chk_send_list, counter));
|
|
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
// create list of glb_vtx
|
|
h5_glb_vertex_t* glb_vtx = NULL;
|
|
h5_int32_t num_glb_vtx = 0;
|
|
TRY (glb_vtx = h5_calloc (4 * num_glb_elems, sizeof (*glb_vtx))); // TODO should be by far enough -> could be optimzed
|
|
TRY (h5tpriv_init_glb_vtx_struct_chk (m, glb_elems, num_glb_elems, glb_vtx, &num_glb_vtx));
|
|
|
|
// get list of chunks to retrieve
|
|
h5_chk_idx_t* chk_list_read = NULL;
|
|
int num_chk_list_read = 0;
|
|
TRY (h5tpriv_get_list_of_chunks_to_read(m, &chk_list_read, &num_chk_list_read));
|
|
TRY (get_list_of_chunks_to_retrieve (m, chk_list_read, &num_chk_list_read));
|
|
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
// exchange cells and vertices
|
|
h5_glb_elem_t* tot_glb_elems = NULL;
|
|
h5_glb_vertex_t* tot_glb_vtx = NULL;
|
|
int num_tot_glb_elems = 0;
|
|
int num_tot_glb_vtx = 0;
|
|
TRY (exchange_glb_elem_glb_vtx (m, glb_elems, num_glb_elems,
|
|
&tot_glb_elems, &num_tot_glb_elems,
|
|
glb_vtx, num_glb_vtx,
|
|
&tot_glb_vtx, &num_tot_glb_vtx));
|
|
TRY (h5_free (glb_elems)); // doesn't that create mem leak?
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
|
|
h5_debug("store exchanged elems");
|
|
// store elems & vertices
|
|
TRY (store_exchanged_elems (m, chk_list_read, num_chk_list_read, tot_glb_elems, num_tot_glb_elems, tot_glb_vtx, num_tot_glb_vtx));
|
|
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
|
|
// set variables elems
|
|
m->num_glb_elems[m->leaf_level] = m->num_glb_elems[m->leaf_level - 1] + num_tot_glb_elems ;
|
|
m->num_glb_leaf_elems[m->leaf_level] = m->num_glb_leaf_elems[m->leaf_level - 1] +
|
|
num_tot_glb_elems /h5tpriv_get_num_new_elems(m) * (h5tpriv_get_num_new_elems(m) - 1) ;
|
|
|
|
m->num_interior_elems[m->leaf_level] = m->last_stored_eid + 1;
|
|
m->num_interior_leaf_elems[m->leaf_level] = m->num_interior_leaf_elems[m->leaf_level-1] +
|
|
((m->num_interior_elems[m->leaf_level] - m->num_interior_elems[m->leaf_level-1])/h5tpriv_get_num_new_elems(m) ) *
|
|
(h5tpriv_get_num_new_elems(m) - 1); // can it be calc easier?
|
|
m->last_stored_eid_before_ref = -1;
|
|
|
|
|
|
// set variables vtx
|
|
m->num_glb_vertices[m->leaf_level] = vtx_range[m->f->nprocs];
|
|
m->num_loc_vertices[m->leaf_level] = m->last_stored_vid + 1;
|
|
m->last_stored_vid_before_ref = -1;
|
|
|
|
// update parent elems
|
|
// idea go through all refined elem (they know their parent) and set parent.child_idx to their idx
|
|
// if it is done backwards always the first child will be stored finally -> is optimizable
|
|
for (int i = m->last_stored_eid; i >= m->num_interior_elems[m->leaf_level - 1]; i--) {
|
|
h5_loc_idx_t parent_idx = h5tpriv_get_loc_elem_parent_idx (m, i);
|
|
if (parent_idx > -1) { // there can be elems with on the chunk border that don't have their parents locally available
|
|
// those were refined on a different proc but exchanged to this proc.
|
|
assert (h5tpriv_get_loc_elem_child_idx (m, parent_idx) == -1 ||
|
|
h5tpriv_get_loc_elem_child_idx (m, parent_idx) == i + 1 ||
|
|
h5tpriv_get_loc_elem_child_idx (m, parent_idx) > i - 4);
|
|
TRY (h5tpriv_set_loc_elem_child_idx (m, parent_idx, i));
|
|
}
|
|
}
|
|
h5_debug("end store elems");
|
|
/* mesh specific finalize */
|
|
TRY (m->methods->store->end_store_elems (m));
|
|
|
|
|
|
|
|
// WARNING elements on boundary chunks that lay on proc boundary may not have enough information
|
|
// to update the neighborhood correctly. a possibility would be to send them around again (the proc
|
|
// who owns their chunk has all necessary neighboring chunks i.e. chan update them properly)
|
|
|
|
|
|
//since we need special versions of this function, it was already implemented above
|
|
// i don't know if there is a nice way to separate it also in parallel...
|
|
// TRY (h5t_end_store_elems (m));
|
|
|
|
// memory cleanup
|
|
|
|
TRY (h5_free (vtx_range));
|
|
|
|
TRY (h5_free (chk_list_read));
|
|
TRY (h5priv_free_glb_idxlist (&marked_glb_elems));
|
|
|
|
|
|
marked_glb_elems = NULL;
|
|
H5_CORE_API_RETURN (h5priv_free_loc_idlist (&m->marked_entities));
|
|
|
|
}
|
|
|
|
#endif
|
|
h5_err_t
|
|
h5t_begin_refine_elems (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
TRY (h5tpriv_add_level (m));
|
|
/*
|
|
Pre-allocate space for items to avoid allocating small pieces of
|
|
memory.
|
|
*/
|
|
TRY (h5priv_alloc_loc_idlist (&m->marked_entities, MAX_NUM_ELEMS_TO_REFINE_LOCALLY));
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5t_end_refine_elems (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
if (m->is_chunked) {
|
|
#ifdef PARALLEL_IO
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
h5_glb_idxlist_t* glb_list = NULL;
|
|
h5_oct_point_t* midpoints = NULL;
|
|
TRY (h5t_pre_refine_chk (m, &glb_list, &midpoints));
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
TRY (h5t_refine_marked_elems_chk (m, glb_list, midpoints));
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
TRY (h5_free (midpoints));
|
|
midpoints = NULL;
|
|
TRY (h5t_post_refine_chk (m, glb_list));
|
|
m->mesh_changed = 1;
|
|
TRY (h5priv_mpi_barrier (m->f->props->comm));
|
|
m->timing.measure[m->timing.next_time++] = MPI_Wtime();
|
|
#endif
|
|
} else {
|
|
TRY (h5t_pre_refine (m));
|
|
TRY (h5t_refine_marked_elems (m));
|
|
TRY (h5t_post_refine (m));
|
|
m->mesh_changed = 1;
|
|
}
|
|
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
|
|
h5_err_t
|
|
h5tpriv_init_chunks (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
if (m->chunks != NULL) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INVAL);
|
|
}
|
|
TRY (m->chunks = h5_calloc (1, sizeof (*m->chunks)));
|
|
m->chunks->curr_idx = -1;
|
|
m->chunks->num_alloc = -1;
|
|
m->chunks->num_levels = -1;
|
|
m->chunks->num_chunks_p_level = NULL;
|
|
m->chunks->chunks = NULL;
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5tpriv_grow_chunks (
|
|
h5t_mesh_t* const m,
|
|
h5_chk_idx_t const size
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, size=%d", m, size);
|
|
if (m->chunks->chunks == NULL ) {
|
|
m->chunks->num_alloc = size;
|
|
m->chunks->num_levels = 1;
|
|
TRY (m->chunks->chunks = h5_calloc (size, sizeof (*m->chunks->chunks)));
|
|
TRY (m->chunks->num_chunks_p_level = h5_calloc (
|
|
m->chunks->num_levels,
|
|
sizeof (*m->chunks->num_chunks_p_level)));
|
|
m->chunks->num_chunks_p_level[0] = size;
|
|
} else {
|
|
m->chunks->num_alloc += size;
|
|
m->chunks->num_levels++;
|
|
TRY (m->chunks->chunks = h5_alloc (m->chunks->chunks, (m->chunks->num_alloc)* sizeof (*m->chunks->chunks)));
|
|
TRY (m->chunks->num_chunks_p_level = h5_alloc (
|
|
m->chunks->num_chunks_p_level,
|
|
m->chunks->num_levels * sizeof (*m->chunks->num_chunks_p_level)));
|
|
m->chunks->num_chunks_p_level[m->chunks->num_levels - 1] = size;
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5tpriv_store_chunks (
|
|
h5t_mesh_t* const m,
|
|
h5t_oct_count_list_t* list,
|
|
h5_chk_idx_t num_chunks,
|
|
h5_glb_idx_t* elem_range,
|
|
h5_glb_idx_t* chk_range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, list=%p, num_chunks=%d, "
|
|
"elem_range=%p, chk_range=%p", m, list, num_chunks, elem_range, chk_range);
|
|
|
|
if (list->num_items <= 0) {
|
|
assert (chk_range[m->f->myproc+1] - chk_range[m->f->myproc] == 0);
|
|
assert (elem_range[m->f->myproc+1] - elem_range[m->f->myproc] == 0);
|
|
assert (num_chunks == 0);
|
|
H5_PRIV_FUNC_LEAVE (H5_SUCCESS);
|
|
}
|
|
int counter = 0;
|
|
h5_chk_weight_t weight = 0;
|
|
h5_oct_idx_t oct_idx = -1;
|
|
//h5_lvl_idx_t level = m->leaf_level;
|
|
int tot_loc_elem = 0;
|
|
for (int i = 0; i < list->num_items; i++) {
|
|
|
|
oct_idx = list->items[i].oct;
|
|
counter = list->items[i].count;
|
|
if (m->leaf_level > 0) {
|
|
counter *= h5tpriv_get_num_new_elems (m);
|
|
}
|
|
TRY (h5tpriv_create_chunk (m, oct_idx, elem_range[m->f->myproc] + tot_loc_elem, weight, counter, chk_range));
|
|
tot_loc_elem += counter;
|
|
}
|
|
|
|
if ((m->chunks->curr_idx + 1 != chk_range[m->f->myproc + 1]) ||
|
|
(tot_loc_elem != elem_range[m->f->myproc + 1] - elem_range[m->f->myproc])) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
h5_err_t
|
|
h5tpriv_create_chunk (
|
|
h5t_mesh_t* m,
|
|
h5_oct_idx_t const oct_idx,
|
|
h5_glb_idx_t const first_elem,
|
|
h5_chk_weight_t const weight,
|
|
h5_chk_size_t num_elems,
|
|
h5_glb_idx_t* chk_range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, oct_idx=%d, first_elem=%lld, weight=%lld, num_elems=%d",
|
|
m, oct_idx,(long long) first_elem, (long long) weight, num_elems);
|
|
|
|
if (m->chunks->curr_idx + 1 > m->chunks->num_alloc) {
|
|
H5_PRIV_FUNC_LEAVE (H5_ERR_INTERNAL);
|
|
}
|
|
if (chk_range == NULL) {
|
|
m->chunks->curr_idx++;
|
|
} else {
|
|
// set curr_idx to beginn of chk_range if not there
|
|
if (m->chunks->curr_idx < chk_range[m->f->myproc]) {
|
|
m->chunks->curr_idx = (h5_chk_idx_t) chk_range[m->f->myproc];
|
|
} else {
|
|
// otherwise already in right range, just add one
|
|
m->chunks->curr_idx++;
|
|
}
|
|
// check that curr_idx doesn't leave range
|
|
assert (m->chunks->curr_idx < chk_range[m->f->myproc + 1]);
|
|
}
|
|
|
|
|
|
m->chunks->chunks[m->chunks->curr_idx].idx = m->chunks->curr_idx;
|
|
m->chunks->chunks[m->chunks->curr_idx].oct_idx = oct_idx;
|
|
m->chunks->chunks[m->chunks->curr_idx].elem = first_elem;
|
|
// m->chunks->chunks[m->chunks->curr_idx].elems_subchk = NULL;
|
|
m->chunks->chunks[m->chunks->curr_idx].weight = weight;
|
|
m->chunks->chunks[m->chunks->curr_idx].num_elems = num_elems;
|
|
// m->chunks->chunks[m->chunks->curr_idx].vtx = -2; // TODO remove from chunks
|
|
// m->chunks->chunks[m->chunks->curr_idx].num_vtx = -2; // TODO remove from chunks
|
|
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
#ifdef PARALLEL_IO
|
|
/*
|
|
* exchange newly created chunks
|
|
*/
|
|
|
|
h5_err_t
|
|
h5tpriv_update_chunks (
|
|
h5t_mesh_t* m,
|
|
h5_glb_idx_t* chk_range
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p, chk_range=%p", m, chk_range);
|
|
// range is already known
|
|
int sendcount = chk_range[m->f->myproc + 1 ] - chk_range[m->f->myproc];
|
|
|
|
// sendbuffer
|
|
h5t_chunk_t* sendbuf = NULL;
|
|
TRY (sendbuf = h5_calloc (sendcount, sizeof (*sendbuf)));
|
|
memcpy(sendbuf, &m->chunks->chunks[chk_range[m->f->myproc]], sendcount * sizeof (*m->chunks->chunks));
|
|
|
|
|
|
// recvbuf
|
|
int* recvdisp = NULL;
|
|
int* recvcount = NULL;
|
|
TRY (recvdisp = h5_calloc (m->f->nprocs, sizeof (*recvdisp)));
|
|
TRY (recvcount = h5_calloc (m->f->nprocs, sizeof (*recvcount)));
|
|
recvdisp[0] = 0;
|
|
recvcount[0] = chk_range[1] - chk_range[0];
|
|
for (int i = 1; i < m->f->nprocs; i++) {
|
|
recvdisp[i] = chk_range[i] - chk_range[0];
|
|
recvcount[i] = chk_range[i + 1 ] - chk_range[i];
|
|
}
|
|
|
|
h5priv_mpi_allgatherv(
|
|
sendbuf,
|
|
sendcount,
|
|
h5_dta_types.mpi_chunk,
|
|
&m->chunks->chunks[chk_range[0]],
|
|
recvcount,
|
|
recvdisp,
|
|
h5_dta_types.mpi_chunk,
|
|
m->f->props->comm);
|
|
|
|
m->chunks->curr_idx = chk_range[m->f->nprocs] -1;
|
|
TRY (h5_free (sendbuf));
|
|
TRY (h5_free (recvdisp));
|
|
TRY (h5_free (recvcount));
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
|
|
h5_err_t
|
|
h5tpriv_free_chunks (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
|
|
if (m->chunks != NULL) {
|
|
TRY (h5_free (m->chunks->chunks));
|
|
TRY (h5_free (m->chunks->num_chunks_p_level));
|
|
TRY (h5_free (m->chunks));
|
|
}
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5tpriv_print_chunks (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
h5_debug ("\nPrinting chunks: \n curr_idx: %d\n num_alloc: %d\n num_levels: %d\n\n",
|
|
m->chunks->curr_idx,
|
|
m->chunks->num_alloc,
|
|
m->chunks->num_levels);
|
|
for (int i = 0; i <= m->chunks->curr_idx; i++) {
|
|
h5_debug ("\nchunk: %d \n oct_idx: %d \n elem: %lld \n weight:%lld \n num_elems: %d\n\n",
|
|
m->chunks->chunks[i].idx,
|
|
m->chunks->chunks[i].oct_idx,
|
|
(long long) m->chunks->chunks[i].elem,
|
|
(long long) m->chunks->chunks[i].weight,
|
|
m->chunks->chunks[i].num_elems
|
|
);
|
|
}
|
|
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
|
|
h5_err_t
|
|
h5tpriv_print_oct_userdata (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_PRIV_FUNC_ENTER (h5_err_t, "m=%p", m);
|
|
h5_debug ("\nPrinting oct_userdata: \n curr_idx: %d\n",
|
|
m->octree->current_oct_idx);
|
|
for (int i = 0; i <= m->octree->current_oct_idx; i++) {
|
|
h5_debug ("\n oct_idx: %d \n %d - %d - %d - %d \n\n",
|
|
i,
|
|
((h5t_oct_userdata_t*)m->octree->userdata)[i].idx[0],
|
|
((h5t_oct_userdata_t*)m->octree->userdata)[i].idx[1],
|
|
((h5t_oct_userdata_t*)m->octree->userdata)[i].idx[2],
|
|
((h5t_oct_userdata_t*)m->octree->userdata)[i].idx[3]
|
|
);
|
|
}
|
|
|
|
|
|
H5_PRIV_FUNC_RETURN (H5_SUCCESS);
|
|
}
|
|
#endif
|
|
#if 0
|
|
// index set for DUNE
|
|
h5_err_t
|
|
h5t_create_index_set (
|
|
h5t_mesh_t* const m
|
|
) {
|
|
H5_CORE_API_ENTER (h5_err_t, "m=%p", m);
|
|
int codim;
|
|
int dim = h5tpriv_ref_elem_get_dim (m);
|
|
// todo: check tagset already exist
|
|
TRY (h5t_add_mtagset (m, "__IndexSet__", H5_INT64_T));
|
|
|
|
for (codim = 0; codim <= dim; codim++) {
|
|
h5_glb_idx_t idx = 0;
|
|
h5t_leaf_iterator_t it;
|
|
h5_glb_id_t entity_id;
|
|
TRY (h5t_init_leaf_iterator ((h5t_iterator_t*)&it, m, codim));
|
|
while ((entity_id = it.iter(f, (h5t_iterator_t*)&it)) >= 0) {
|
|
TRY (h5t_set_mtag_by_name (f, "__IndexSet__", entity_id, 1, &idx));
|
|
}
|
|
}
|
|
H5_CORE_API_RETURN (H5_SUCCESS);
|
|
}
|
|
#endif
|