You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
932 lines
31 KiB
932 lines
31 KiB
2 years ago
|
/*
|
||
|
* Copyright(C) 1999-2023 National Technology & Engineering Solutions
|
||
|
* of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
|
||
|
* NTESS, the U.S. Government retains certain rights in this software.
|
||
|
*
|
||
|
* See packages/seacas/LICENSE for details
|
||
|
*/
|
||
|
|
||
|
#include <assert.h>
|
||
|
#include <inttypes.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "exodusII.h"
|
||
|
|
||
|
#define DEFAULT_FILE_NAME "mesh"
|
||
|
#define DEFAULT_MAP_ORIGIN 1
|
||
|
#define DEFAULT_NUM_DOMAINS 1
|
||
|
#define DEFAULT_NUM_ELEMENTS 1000000
|
||
|
#define DEFAULT_NUM_FIELDS 0
|
||
|
#define DEFAULT_NUM_TIMESTEPS 1
|
||
|
|
||
|
#define MAX_STRING_LEN 128
|
||
|
#define NUM_BYTES_PER_INT 4
|
||
|
#define NUM_NODES_PER_ELEM 8
|
||
|
|
||
|
#define EBLK_ID 100000
|
||
|
#define EXODUSII_FILE_TYPE ".e"
|
||
|
|
||
|
typedef double realtyp;
|
||
|
|
||
|
typedef int64_t INT;
|
||
|
|
||
|
INT StringToCount(char *size_str)
|
||
|
{
|
||
|
INT size = 0;
|
||
|
char range;
|
||
|
int rc;
|
||
|
|
||
|
rc = sscanf(size_str, "%" PRId64 "%c", &size, &range);
|
||
|
if (rc == 2) {
|
||
|
switch ((int)range) {
|
||
|
case 'k':
|
||
|
case 'K': size *= 1000; break;
|
||
|
case 'm':
|
||
|
case 'M': size *= 1000000; break;
|
||
|
case 'g':
|
||
|
case 'G': size *= 1000000000; break;
|
||
|
}
|
||
|
}
|
||
|
else if (rc == 0) {
|
||
|
size = -1;
|
||
|
}
|
||
|
return (size);
|
||
|
} /* StringToCount() */
|
||
|
|
||
|
void get_file_name(const char *base, const char *ext, int rank, int nprocs, const char *other,
|
||
|
char *output);
|
||
|
|
||
|
/* We need to do a cube-root to find the number of elements on each
|
||
|
* side of the cube, but don't want to link in -lm just for
|
||
|
* this. Use this routine which is better than
|
||
|
* a brute force approach. Found at
|
||
|
* http://www.hackersdelight.org/HDcode/icbrt.c
|
||
|
*/
|
||
|
INT icbrt(unsigned x)
|
||
|
{
|
||
|
INT s = 30;
|
||
|
unsigned y = 0;
|
||
|
while (s >= 0) { /* Do 11 times. */
|
||
|
y = 2 * y;
|
||
|
unsigned b = (3 * y * (y + 1) + 1) << s;
|
||
|
s = s - 3;
|
||
|
if (x >= b) {
|
||
|
x = x - b;
|
||
|
y = y + 1;
|
||
|
}
|
||
|
}
|
||
|
return y;
|
||
|
}
|
||
|
|
||
|
/* Prototypes */
|
||
|
void create_rr_elem_map(INT loc_num_elements, INT *elem_map, INT map_origin, INT num_domains,
|
||
|
INT current_domain);
|
||
|
|
||
|
void create_elem_map(INT loc_num_elems, INT elem_num, INT *elem_map, INT map_origin);
|
||
|
|
||
|
void create_local_connect(INT *node_map, INT len_node_map, INT len_connect, INT *domain_connect,
|
||
|
INT *loc_connect, INT map_origin);
|
||
|
|
||
|
void extract_connect(INT element_offset, INT num_elem, INT *elem_map, INT *connect,
|
||
|
INT *domain_connect, INT map_origin);
|
||
|
|
||
|
void make_mesh(realtyp *x, realtyp *y, realtyp *z, INT *connect, INT map_origin,
|
||
|
INT num_elements_1d);
|
||
|
|
||
|
void parse_input(int argc, char *argv[], bool *debug, INT *map_origin, INT *num_elements_1d,
|
||
|
INT *num_domains, INT *num_nodal_fields, INT *num_global_fields,
|
||
|
INT *num_element_fields, INT *num_timesteps, char *file_name, int *exodus,
|
||
|
int *compression_level, int *shuffle, int *int64bit);
|
||
|
|
||
|
void write_exo_mesh(int debug, char *file_name, INT map_origin, INT num_nodes, INT num_elements,
|
||
|
INT num_domains, INT num_nodal_fields, INT num_global_fields,
|
||
|
INT num_element_fields, INT num_timesteps, realtyp *x, realtyp *y, realtyp *z,
|
||
|
INT *connect, int compression_level, int shuffle, int int64bit);
|
||
|
|
||
|
void create_node_map(INT len_map, INT len_connect, INT *domain_connect, INT *node_map,
|
||
|
INT *loc_num_nodes, INT map_origin);
|
||
|
|
||
|
INT bin_search2(INT value, INT num, INT List[]);
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Main function
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
|
||
|
int main(int argc, char *argv[])
|
||
|
{
|
||
|
INT *connect;
|
||
|
bool debug = false; /* true, display debug information; false */
|
||
|
/* otherwise. */
|
||
|
static char file_name[MAX_STRING_LEN] = DEFAULT_FILE_NAME;
|
||
|
int exodus = true;
|
||
|
INT map_origin = DEFAULT_MAP_ORIGIN;
|
||
|
INT num_domains = DEFAULT_NUM_DOMAINS;
|
||
|
INT num_elements_1d;
|
||
|
INT num_elements = DEFAULT_NUM_ELEMENTS;
|
||
|
INT num_nodal_fields = DEFAULT_NUM_FIELDS;
|
||
|
INT num_global_fields = DEFAULT_NUM_FIELDS;
|
||
|
INT num_element_fields = DEFAULT_NUM_FIELDS;
|
||
|
INT num_timesteps = DEFAULT_NUM_TIMESTEPS;
|
||
|
INT num_nodes;
|
||
|
int compression_level = 0;
|
||
|
int shuffle = 0;
|
||
|
int int64bit = 0;
|
||
|
size_t size;
|
||
|
|
||
|
ex_opts(EX_VERBOSE | EX_ABORT);
|
||
|
|
||
|
/* Parse Input */
|
||
|
parse_input(argc, argv, &debug, &map_origin, &num_elements, &num_domains, &num_nodal_fields,
|
||
|
&num_global_fields, &num_element_fields, &num_timesteps, file_name, &exodus,
|
||
|
&compression_level, &shuffle, &int64bit);
|
||
|
|
||
|
/* Create Coordinates and Connectivity Array */
|
||
|
num_elements_1d = icbrt(num_elements);
|
||
|
num_nodes = (num_elements_1d + 1) * (num_elements_1d + 1) * (num_elements_1d + 1);
|
||
|
realtyp *x = malloc(num_nodes * sizeof(realtyp));
|
||
|
realtyp *y = malloc(num_nodes * sizeof(realtyp));
|
||
|
realtyp *z = malloc(num_nodes * sizeof(realtyp));
|
||
|
assert(x != NULL && y != NULL && z != NULL);
|
||
|
|
||
|
num_elements = num_elements_1d * num_elements_1d * num_elements_1d;
|
||
|
size = (size_t)NUM_NODES_PER_ELEM * num_elements * sizeof(INT);
|
||
|
assert(size > 0);
|
||
|
connect = malloc(size);
|
||
|
assert(connect != NULL);
|
||
|
|
||
|
fprintf(stderr, "Creating a 3D mesh of %" PRId64 " hex elements and %" PRId64 " nodes.\n",
|
||
|
num_elements, num_nodes);
|
||
|
|
||
|
make_mesh(x, y, z, connect, map_origin, num_elements_1d);
|
||
|
fprintf(stderr, "\t...Mesh topology created.\n");
|
||
|
|
||
|
/*
|
||
|
* Write Out Mesh
|
||
|
*/
|
||
|
|
||
|
if (exodus) {
|
||
|
write_exo_mesh(debug, file_name, map_origin, num_nodes, num_elements, num_domains,
|
||
|
num_nodal_fields, num_global_fields, num_element_fields, num_timesteps, x, y, z,
|
||
|
connect, compression_level, shuffle, int64bit);
|
||
|
}
|
||
|
|
||
|
free(x);
|
||
|
free(y);
|
||
|
free(z);
|
||
|
free(connect);
|
||
|
return 0;
|
||
|
} /* end of main() */
|
||
|
|
||
|
/***********************************************************************
|
||
|
***********************************************************************/
|
||
|
void parse_input(int argc, char *argv[], bool *debug, INT *map_origin, INT *num_elements_1d,
|
||
|
INT *num_domains, INT *num_nodal_fields, INT *num_global_fields,
|
||
|
INT *num_element_fields, INT *num_timesteps, char *file_name, int *exodus,
|
||
|
int *compression_level, int *shuffle, int *int64bit)
|
||
|
{
|
||
|
int arg = 0; /* Argument index. */
|
||
|
|
||
|
while (++arg < argc) {
|
||
|
if (strcmp("-c", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_nodal_fields = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-compress", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*compression_level = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-shuffle", argv[arg]) == 0) {
|
||
|
*shuffle = 1;
|
||
|
}
|
||
|
else if (strcmp("-64", argv[arg]) == 0) {
|
||
|
*int64bit = 1;
|
||
|
}
|
||
|
else if (strcmp("-nv", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_nodal_fields = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-gv", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_global_fields = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-ev", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_element_fields = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-t", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_timesteps = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-d", argv[arg]) == 0) {
|
||
|
*debug = true;
|
||
|
}
|
||
|
else if (strcmp("-f", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
ex_copy_string(file_name, argv[arg], MAX_STRING_LEN);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-m", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*map_origin = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-n", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_elements_1d = StringToCount(argv[arg]);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-p", argv[arg]) == 0) {
|
||
|
if (++arg < argc) {
|
||
|
*num_domains = strtol(argv[arg], NULL, 10);
|
||
|
}
|
||
|
}
|
||
|
else if (strcmp("-x", argv[arg]) == 0) {
|
||
|
*exodus = true;
|
||
|
}
|
||
|
else if ((strcmp("-h", argv[arg]) == 0) || (strcmp("-u", argv[arg]) == 0)) {
|
||
|
printf(" \n");
|
||
|
printf("NAME \n");
|
||
|
printf(" \n");
|
||
|
printf("create_mesh - creates a mesh file for performance benchmarking. \n");
|
||
|
printf(" \n");
|
||
|
printf("SYNOPSIS \n");
|
||
|
printf(" \n");
|
||
|
printf("create_mesh [-c fields] [-t timesteps] [-d] [-f file_name] \n");
|
||
|
printf(" [-m map_origin] [-n elements] [-p domains] \n");
|
||
|
printf(" [-nv number] [-ev number] [-gv number] ");
|
||
|
printf(" [-r] [-u] [-h] ");
|
||
|
printf("[-x]");
|
||
|
printf(" \n");
|
||
|
printf(" \n");
|
||
|
printf("DESCRIPTION \n");
|
||
|
printf(" \n");
|
||
|
printf("This program creates a 3-D mesh for performance benchmarking. \n");
|
||
|
printf("The EXODUSII II database file(s) created by this \n");
|
||
|
printf("prrogram is/are read by the rd_wt_mesh program to perform the \n");
|
||
|
printf("actual benchmark. \n");
|
||
|
printf(" \n");
|
||
|
printf("OPTIONS \n");
|
||
|
printf(" \n");
|
||
|
printf("-c fields number of nodal fields. Default: %d \n",
|
||
|
DEFAULT_NUM_FIELDS);
|
||
|
printf("-nv fields number of nodal fields. Default: %d \n",
|
||
|
DEFAULT_NUM_FIELDS);
|
||
|
printf("-ev fields number of element fields. Default: %d \n",
|
||
|
DEFAULT_NUM_FIELDS);
|
||
|
printf("-gv fields number of global fields. Default: %d \n",
|
||
|
DEFAULT_NUM_FIELDS);
|
||
|
printf("-t timesteps number of timesteps. Default: %d \n",
|
||
|
DEFAULT_NUM_TIMESTEPS);
|
||
|
printf("-d display debug information. \n");
|
||
|
printf("-f file_name file name prefix for all created files: \n");
|
||
|
printf(" \n");
|
||
|
printf(" 'file_name'_n%s [EXODUSII II file] \n",
|
||
|
EXODUSII_FILE_TYPE);
|
||
|
printf(" \n");
|
||
|
printf(" where n varies from 0 to number of domains-1. \n");
|
||
|
printf(" Default: %s \n",
|
||
|
DEFAULT_FILE_NAME);
|
||
|
printf("-h display help/usage information. \n");
|
||
|
printf("-m map_origin element map origin. Default: %d \n",
|
||
|
DEFAULT_MAP_ORIGIN);
|
||
|
printf("-n elements number of elements in mesh \n");
|
||
|
printf(" Can suffix with 'k', 'm', 'g' for thousand, million, billion\n");
|
||
|
printf(" elements/file = elements/number_of_domains. \n");
|
||
|
printf(" Default: %d \n",
|
||
|
DEFAULT_NUM_ELEMENTS);
|
||
|
printf("-p domains number of domains. Default: %d \n",
|
||
|
DEFAULT_NUM_DOMAINS);
|
||
|
printf("-compress val set compression to level 'val' [0..9] \n");
|
||
|
printf("-shuffle enable hdf5-shuffle \n");
|
||
|
printf("-64 enable 64-bit integers \n");
|
||
|
printf("-u display help/usage information. \n");
|
||
|
|
||
|
exit(0);
|
||
|
}
|
||
|
else {
|
||
|
fprintf(stderr, "Unknown option: %s\n", argv[arg]);
|
||
|
fprintf(stderr, "Enter create_mesh -h for description of valid options.\n");
|
||
|
|
||
|
exit(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Create the coordinates and connectivity array for the mesh
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
|
||
|
void make_mesh(realtyp *x, realtyp *y, realtyp *z, INT *connect, INT map_origin,
|
||
|
INT num_elements_1d)
|
||
|
{
|
||
|
/* create global coordinates */
|
||
|
size_t k = 0;
|
||
|
for (size_t m = 0; m < (num_elements_1d + 1); m++) {
|
||
|
for (size_t i = 0; i < (num_elements_1d + 1); i++) {
|
||
|
for (size_t j = 0; j < (num_elements_1d + 1); j++, k++) {
|
||
|
x[k] = (realtyp)j;
|
||
|
y[k] = (realtyp)i;
|
||
|
z[k] = (realtyp)m;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* build connectivity array (node list) for mesh */
|
||
|
size_t elp1sq = (num_elements_1d + 1) * (num_elements_1d + 1);
|
||
|
size_t cnt = 0;
|
||
|
for (size_t m = 0; m < num_elements_1d; m++) {
|
||
|
k = 0;
|
||
|
for (size_t i = 0; i < num_elements_1d; i++) {
|
||
|
for (size_t j = 0; j < num_elements_1d; j++, k++) {
|
||
|
size_t base = (m * elp1sq) + k + i + map_origin;
|
||
|
connect[cnt++] = base;
|
||
|
connect[cnt++] = base + 1;
|
||
|
connect[cnt++] = base + num_elements_1d + 2;
|
||
|
connect[cnt++] = base + num_elements_1d + 1;
|
||
|
|
||
|
connect[cnt++] = elp1sq + base;
|
||
|
connect[cnt++] = elp1sq + base + 1;
|
||
|
connect[cnt++] = elp1sq + base + num_elements_1d + 2;
|
||
|
connect[cnt++] = elp1sq + base + num_elements_1d + 1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} /* end of make_mesh() */
|
||
|
|
||
|
/***********************************************************************
|
||
|
***********************************************************************/
|
||
|
void write_exo_mesh(int debug, char *file_name, INT map_origin, INT num_nodes, INT num_elements,
|
||
|
INT num_domains, INT num_nodal_fields, INT num_global_fields,
|
||
|
INT num_element_fields, INT num_timesteps, realtyp *x, realtyp *y, realtyp *z,
|
||
|
INT *connect, int compression_level, int shuffle, int int64bit)
|
||
|
{
|
||
|
realtyp *loc_xcoords = NULL;
|
||
|
realtyp *loc_ycoords = NULL;
|
||
|
realtyp *loc_zcoords = NULL;
|
||
|
realtyp *globals = NULL;
|
||
|
|
||
|
INT accum_num_elements = 0;
|
||
|
INT loc_num_elements, loc_num_nodes;
|
||
|
INT *elem_map = NULL;
|
||
|
INT *node_map = NULL;
|
||
|
INT *domain_connect = NULL;
|
||
|
INT *loc_connect = NULL;
|
||
|
|
||
|
for (INT i = 0; i < num_domains; i++) {
|
||
|
int mymode = EX_MAPS_INT64_API | EX_BULK_INT64_API | EX_IDS_INT64_API;
|
||
|
if (int64bit) {
|
||
|
mymode |= EX_MAPS_INT64_DB | EX_BULK_INT64_DB | EX_IDS_INT64_DB;
|
||
|
}
|
||
|
|
||
|
/* create the EXODUSII file */
|
||
|
char temporary_name[MAX_STRING_LEN];
|
||
|
get_file_name(file_name, "e", i, num_domains, NULL, temporary_name);
|
||
|
|
||
|
int CPU_word_size = sizeof(realtyp);
|
||
|
int IO_word_size = sizeof(realtyp);
|
||
|
int exoid = ex_create(temporary_name, EX_CLOBBER | mymode, &CPU_word_size, &IO_word_size);
|
||
|
|
||
|
if (exoid < 0) {
|
||
|
fprintf(stderr, "after ex_create, error = %d\n", exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
ex_set_option(exoid, EX_OPT_COMPRESSION_LEVEL, compression_level);
|
||
|
ex_set_option(exoid, EX_OPT_COMPRESSION_SHUFFLE, shuffle);
|
||
|
|
||
|
if (num_domains > 1) {
|
||
|
/* Determine local number of elements */
|
||
|
if (num_elements < num_domains) {
|
||
|
fprintf(stderr, "number of elements is less than number of domains.\n");
|
||
|
if (i < num_elements) {
|
||
|
loc_num_elements = 1;
|
||
|
}
|
||
|
else {
|
||
|
loc_num_elements = 0;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
loc_num_elements = num_elements / num_domains;
|
||
|
if (i < (num_elements % num_domains)) {
|
||
|
loc_num_elements++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* malloc things we need */
|
||
|
INT len_connect = NUM_NODES_PER_ELEM * loc_num_elements;
|
||
|
if (i == 0) { /* first time through; max size arrays occur on
|
||
|
first iteration */
|
||
|
elem_map = malloc(loc_num_elements * sizeof(INT));
|
||
|
domain_connect = malloc(len_connect * sizeof(INT));
|
||
|
loc_connect = malloc(len_connect * sizeof(INT));
|
||
|
node_map = malloc(num_nodes * sizeof(INT));
|
||
|
}
|
||
|
|
||
|
/* Create element local/global map */
|
||
|
create_elem_map(loc_num_elements, accum_num_elements, elem_map, map_origin);
|
||
|
|
||
|
/* Extract current domain's connectivity, referencing global node ids */
|
||
|
extract_connect(accum_num_elements, loc_num_elements, elem_map, connect, domain_connect,
|
||
|
map_origin);
|
||
|
|
||
|
accum_num_elements += loc_num_elements;
|
||
|
|
||
|
/* The local/global node map is just the current domain's connectivity,
|
||
|
sorted with duplicate entries removed */
|
||
|
create_node_map(num_nodes, len_connect, domain_connect, node_map, &loc_num_nodes, map_origin);
|
||
|
|
||
|
/* Using local/global node map, convert the domain connectivity
|
||
|
(referencing global node ids) to local connectivity (referencing
|
||
|
local node ids) */
|
||
|
|
||
|
create_local_connect(node_map, loc_num_nodes, len_connect, domain_connect, loc_connect,
|
||
|
map_origin);
|
||
|
}
|
||
|
else {
|
||
|
loc_num_elements = num_elements;
|
||
|
loc_num_nodes = num_nodes;
|
||
|
}
|
||
|
|
||
|
if (debug) {
|
||
|
fprintf(stderr, "\n\n\n");
|
||
|
|
||
|
fprintf(stderr, "\n domain: %" PRId64 "\n", i);
|
||
|
fprintf(stderr, "\n loc_num_elements: %" PRId64 "\n", loc_num_elements);
|
||
|
fprintf(stderr, "\n loc_num_nodes: %" PRId64 "\n", loc_num_nodes);
|
||
|
}
|
||
|
|
||
|
int num_dim = 3;
|
||
|
int num_elem_blk = 1;
|
||
|
int num_node_sets = 0;
|
||
|
int num_side_sets = 0;
|
||
|
|
||
|
int err = ex_put_init(exoid, "This is an EXODUSII performance test.", num_dim, loc_num_nodes,
|
||
|
loc_num_elements, num_elem_blk, num_node_sets, num_side_sets);
|
||
|
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_init, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
/* Extract the local x and y coordinates */
|
||
|
if (num_domains > 1) {
|
||
|
INT loc_node_size = -1;
|
||
|
if (loc_num_nodes > loc_node_size) {
|
||
|
realtyp *tmpx = realloc(loc_xcoords, loc_num_nodes * sizeof(realtyp));
|
||
|
if (tmpx == NULL) {
|
||
|
free(loc_xcoords);
|
||
|
fprintf(stderr, "error realloc'ing loc_xcoords\n");
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
{
|
||
|
loc_xcoords = tmpx;
|
||
|
}
|
||
|
realtyp *tmpy = realloc(loc_ycoords, loc_num_nodes * sizeof(realtyp));
|
||
|
if (tmpy == NULL) {
|
||
|
free(loc_ycoords);
|
||
|
fprintf(stderr, "error realloc'ing loc_ycoords\n");
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
{
|
||
|
loc_ycoords = tmpy;
|
||
|
}
|
||
|
realtyp *tmpz = realloc(loc_zcoords, loc_num_nodes * sizeof(realtyp));
|
||
|
if (tmpz == NULL) {
|
||
|
free(loc_zcoords);
|
||
|
fprintf(stderr, "error realloc'ing loc_zcoords\n");
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
{
|
||
|
loc_zcoords = tmpz;
|
||
|
}
|
||
|
loc_node_size = loc_num_nodes;
|
||
|
}
|
||
|
|
||
|
for (INT j = 0; j < loc_num_nodes; j++) {
|
||
|
INT index = node_map[j] - map_origin;
|
||
|
loc_xcoords[j] = x[index];
|
||
|
loc_ycoords[j] = y[index];
|
||
|
loc_zcoords[j] = z[index];
|
||
|
}
|
||
|
|
||
|
err = ex_put_coord(exoid, loc_xcoords, loc_ycoords, loc_zcoords);
|
||
|
}
|
||
|
else {
|
||
|
err = ex_put_coord(exoid, x, y, z);
|
||
|
}
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_coord, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
if (debug) {
|
||
|
fprintf(stderr, "\tCoordinates output.\n");
|
||
|
}
|
||
|
#if 1
|
||
|
{
|
||
|
INT ids[1] = {EBLK_ID};
|
||
|
INT num_elem_per_block[1];
|
||
|
char *names[1] = {"hex"};
|
||
|
INT num_node_per_elem[1];
|
||
|
INT num_attr_per_block[1];
|
||
|
bool write_map = num_domains > 1 ? true : false;
|
||
|
num_elem_per_block[0] = loc_num_elements;
|
||
|
num_node_per_elem[0] = NUM_NODES_PER_ELEM;
|
||
|
num_attr_per_block[0] = 0;
|
||
|
err = ex_put_concat_elem_block(exoid, ids, names, num_elem_per_block, num_node_per_elem,
|
||
|
num_attr_per_block, write_map);
|
||
|
}
|
||
|
#else
|
||
|
err = ex_put_block(exoid, EX_ELEM_BLOCK, 10000000000, "hex", loc_num_elements,
|
||
|
NUM_NODES_PER_ELEM, 0);
|
||
|
#endif
|
||
|
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_elem_block, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
if (num_domains > 1) {
|
||
|
err = ex_put_conn(exoid, EX_ELEM_BLOCK, EBLK_ID, loc_connect, NULL, NULL);
|
||
|
}
|
||
|
else {
|
||
|
err = ex_put_conn(exoid, EX_ELEM_BLOCK, EBLK_ID, connect, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_elem_conn, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
if (debug) {
|
||
|
fprintf(stderr, "\tConnectivity output.\n");
|
||
|
}
|
||
|
/* write out element and node maps */
|
||
|
|
||
|
if (num_domains > 1) {
|
||
|
err = ex_put_id_map(exoid, EX_NODE_MAP, node_map);
|
||
|
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_id_map, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
err = ex_put_id_map(exoid, EX_ELEM_MAP, elem_map);
|
||
|
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_id_map, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
if (debug) {
|
||
|
fprintf(stderr, "\tMaps output.\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* write out simulated results fields;
|
||
|
we'll just write out the x coordinate field 'num_nodal_fields' times */
|
||
|
if (loc_num_nodes < loc_num_elements) {
|
||
|
fprintf(stderr, "INTERNAL ERROR: Programmer assumed number of nodes > number of elements, "
|
||
|
"but that is not true.\n");
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
int *elem_var_tab = NULL;
|
||
|
if (num_element_fields > 0) {
|
||
|
elem_var_tab = malloc(num_element_fields * sizeof(int));
|
||
|
for (INT j = 0; j < num_element_fields; j++) {
|
||
|
elem_var_tab[j] = 1;
|
||
|
}
|
||
|
}
|
||
|
err = ex_put_all_var_param(exoid, num_global_fields, num_nodal_fields, num_element_fields,
|
||
|
elem_var_tab, 0, 0, 0, 0);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_all_var_param, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
|
||
|
char **var_name;
|
||
|
if (num_nodal_fields > 0) {
|
||
|
|
||
|
var_name = malloc(num_nodal_fields * sizeof(char *));
|
||
|
for (INT j = 0; j < num_nodal_fields; j++) {
|
||
|
var_name[j] = malloc((MAX_STRING_LEN + 1) * sizeof(char));
|
||
|
snprintf(var_name[j], MAX_STRING_LEN + 1, "node_field_%" PRId64, j + 1);
|
||
|
}
|
||
|
err = ex_put_variable_names(exoid, EX_NODAL, num_nodal_fields, var_name);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_variable_names (nodal), error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
for (INT j = 0; j < num_nodal_fields; j++) {
|
||
|
free(var_name[j]);
|
||
|
}
|
||
|
free(var_name);
|
||
|
}
|
||
|
|
||
|
if (num_global_fields > 0) {
|
||
|
globals = malloc(num_global_fields * sizeof(realtyp));
|
||
|
var_name = malloc(num_global_fields * sizeof(char *));
|
||
|
for (INT j = 0; j < num_global_fields; j++) {
|
||
|
var_name[j] = malloc((MAX_STRING_LEN + 1) * sizeof(char));
|
||
|
snprintf(var_name[j], MAX_STRING_LEN + 1, "global_field_%" PRId64, j + 1);
|
||
|
globals[j] = j;
|
||
|
}
|
||
|
err = ex_put_variable_names(exoid, EX_GLOBAL, num_global_fields, var_name);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_variable_names (global), error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
for (INT j = 0; j < num_global_fields; j++) {
|
||
|
free(var_name[j]);
|
||
|
}
|
||
|
free(var_name);
|
||
|
}
|
||
|
|
||
|
if (num_element_fields > 0) {
|
||
|
free(elem_var_tab);
|
||
|
var_name = malloc(num_element_fields * sizeof(char *));
|
||
|
for (INT j = 0; j < num_element_fields; j++) {
|
||
|
var_name[j] = malloc((MAX_STRING_LEN + 1) * sizeof(char));
|
||
|
snprintf(var_name[j], MAX_STRING_LEN + 1, "element_field_%" PRId64, j + 1);
|
||
|
}
|
||
|
err = ex_put_variable_names(exoid, EX_ELEM_BLOCK, num_element_fields, var_name);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_variable_names, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
for (INT j = 0; j < num_element_fields; j++) {
|
||
|
free(var_name[j]);
|
||
|
}
|
||
|
free(var_name);
|
||
|
}
|
||
|
|
||
|
if (num_nodal_fields + num_global_fields + num_element_fields > 0) {
|
||
|
fprintf(stderr, "Domain %" PRId64 "/%" PRId64 ", Writing Timestep: ", i + 1, num_domains);
|
||
|
for (INT t = 0; t < num_timesteps; t++) {
|
||
|
realtyp time = t;
|
||
|
ex_put_time(exoid, t + 1, &time);
|
||
|
fprintf(stderr, "%" PRId64 ", ", t + 1);
|
||
|
if (num_global_fields > 0) {
|
||
|
err = ex_put_var(exoid, t + 1, EX_GLOBAL, 1, 0, num_global_fields, globals);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_global_var, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
for (INT j = 0; j < num_nodal_fields; j++) {
|
||
|
err = ex_put_var(exoid, t + 1, EX_NODAL, j + 1, 0, loc_num_nodes, x);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_nodal_var, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
for (INT j = 0; j < num_element_fields; j++) {
|
||
|
err = ex_put_var(exoid, t + 1, EX_ELEM_BLOCK, j + 1, EBLK_ID, loc_num_elements, x);
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_put_element_var, error = %d\n", err);
|
||
|
ex_close(exoid);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
fprintf(stderr, "\n");
|
||
|
}
|
||
|
|
||
|
err = ex_close(exoid);
|
||
|
|
||
|
if (err) {
|
||
|
fprintf(stderr, "after ex_close, error = %d\n", err);
|
||
|
exit(-1);
|
||
|
}
|
||
|
if (debug) {
|
||
|
fprintf(stderr, "\tFile written.\n");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Free Memory
|
||
|
*/
|
||
|
|
||
|
if (num_domains > 1) {
|
||
|
free(domain_connect);
|
||
|
free(elem_map);
|
||
|
free(loc_connect);
|
||
|
free(loc_xcoords);
|
||
|
free(loc_ycoords);
|
||
|
free(loc_zcoords);
|
||
|
free(node_map);
|
||
|
}
|
||
|
if (num_global_fields > 0) {
|
||
|
free(globals);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Create element local/global map
|
||
|
*
|
||
|
* This puts contiguous groups of elements in each domain. This is
|
||
|
* a somewhat reasonable map for a realistic application.
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
void create_elem_map(INT loc_num_elems, INT elem_num, INT *elem_map, INT map_origin)
|
||
|
{
|
||
|
for (INT i = 0; i < loc_num_elems; i++) {
|
||
|
elem_map[i] = map_origin + elem_num++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Extract current domain's connectivity, referencing global node ids
|
||
|
*
|
||
|
* This extracts the "domain connectivity," that is, the connectivity
|
||
|
* of the elements in the current domain. The node ids in the domain
|
||
|
* connectivity reference global node ids.
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
|
||
|
void extract_connect(INT element_offset, INT num_elem, INT *elem_map, INT *connect,
|
||
|
INT *domain_connect, INT map_origin)
|
||
|
{
|
||
|
INT i = element_offset;
|
||
|
INT m = 0;
|
||
|
for (INT j = 0; j < num_elem; j++) {
|
||
|
if (elem_map[j] == i + map_origin) { /* extract this element */
|
||
|
INT offset = (i * NUM_NODES_PER_ELEM);
|
||
|
for (INT k = offset; k < offset + NUM_NODES_PER_ELEM; k++) {
|
||
|
domain_connect[m++] = connect[k];
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* The local/global node map is just the current domain's connectivity,
|
||
|
* sorted, with duplicate entries removed. This isn't obvious, but
|
||
|
* trust me.
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
void create_node_map(INT len_map, INT len_connect, INT *domain_connect, INT *node_map,
|
||
|
INT *loc_num_nodes, INT map_origin)
|
||
|
{
|
||
|
for (INT i = 0; i < len_map; i++) {
|
||
|
node_map[i] = 0;
|
||
|
}
|
||
|
|
||
|
for (INT i = 0; i < len_connect; i++) {
|
||
|
node_map[domain_connect[i] - map_origin] = 1;
|
||
|
}
|
||
|
|
||
|
INT cnt = 0;
|
||
|
for (INT i = 0; i < len_map; i++) {
|
||
|
if (node_map[i] > 0) {
|
||
|
node_map[cnt++] = i + map_origin;
|
||
|
}
|
||
|
}
|
||
|
*loc_num_nodes = cnt;
|
||
|
}
|
||
|
|
||
|
/***********************************************************************
|
||
|
*
|
||
|
* Using local/global node map, convert the domain connectivity
|
||
|
* (referencing global node ids) to local connectivity (referencing
|
||
|
* local node ids).
|
||
|
*
|
||
|
* This requires inverting the local/global map, a relatively expensive
|
||
|
* operation. The procedure is:
|
||
|
*
|
||
|
* for every entry in the domain connectivity
|
||
|
* search the node map until found
|
||
|
* set the value of the entry in the local connectivity to
|
||
|
* the index of the located value in the node map
|
||
|
*
|
||
|
***********************************************************************/
|
||
|
void create_local_connect(INT *node_map, INT len_node_map, INT len_connect, INT *domain_connect,
|
||
|
INT *loc_connect, INT map_origin)
|
||
|
{
|
||
|
for (INT i = 0; i < len_connect; i++) {
|
||
|
INT index = bin_search2(domain_connect[i], len_node_map, node_map);
|
||
|
if (index != -1) { /* found */
|
||
|
loc_connect[i] = index + map_origin;
|
||
|
}
|
||
|
else {
|
||
|
fprintf(stderr, "error creating local connectivity; i = %" PRId64 "\n", i);
|
||
|
exit(-1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************
|
||
|
*
|
||
|
* Searches a monotonic list of values for the value, 'value'.
|
||
|
* It returns the index (0-based) of the first position found, which
|
||
|
* matches 'value'.
|
||
|
* The list is assumed to be monotonic, and consist of elements
|
||
|
* list[0], ..., list[n-1].
|
||
|
* If no position in list matches value, it returns the value -1.
|
||
|
*
|
||
|
*****************************************************************************/
|
||
|
|
||
|
INT bin_search2(INT value, INT num, INT List[])
|
||
|
{
|
||
|
INT bottom = 0;
|
||
|
INT top = num - 1;
|
||
|
while (bottom <= top) {
|
||
|
INT middle = (bottom + top) >> 1;
|
||
|
INT g_mid = List[middle];
|
||
|
if (value < g_mid) {
|
||
|
top = middle - 1;
|
||
|
}
|
||
|
else if (value > g_mid) {
|
||
|
bottom = middle + 1;
|
||
|
}
|
||
|
else {
|
||
|
return middle; /* found */
|
||
|
}
|
||
|
}
|
||
|
return -1;
|
||
|
} /* bin_search2 */
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
void get_file_name(const char *base, const char *ext, int rank, int nprocs, const char *other,
|
||
|
char *output)
|
||
|
{
|
||
|
|
||
|
output[0] = '\0';
|
||
|
ex_copy_string(output, base, MAX_STRING_LEN);
|
||
|
strcat(output, ".");
|
||
|
strcat(output, ext);
|
||
|
if (other != NULL) {
|
||
|
strcat(output, ".");
|
||
|
strcat(output, other);
|
||
|
}
|
||
|
if (nprocs > 1) {
|
||
|
/*
|
||
|
* Find out the number of digits needed to specify the processor ID.
|
||
|
* This allows numbers like 01-99, i.e., prepending zeros to the
|
||
|
* name to preserve proper alphabetic sorting of the files.
|
||
|
*/
|
||
|
INT iMaxDigit = 0, iMyDigit = 0;
|
||
|
INT iTemp1 = nprocs;
|
||
|
do {
|
||
|
iTemp1 /= 10;
|
||
|
iMaxDigit++;
|
||
|
} while (iTemp1 >= 1);
|
||
|
|
||
|
iTemp1 = rank;
|
||
|
do {
|
||
|
iTemp1 /= 10;
|
||
|
iMyDigit++;
|
||
|
} while (iTemp1 >= 1);
|
||
|
|
||
|
char cTemp[128];
|
||
|
snprintf(cTemp, 128, "%d", nprocs);
|
||
|
|
||
|
strcat(output, ".");
|
||
|
strcat(output, cTemp);
|
||
|
strcat(output, ".");
|
||
|
|
||
|
/*
|
||
|
* Append the proper number of zeros to the filename.
|
||
|
*/
|
||
|
for (INT i1 = 0; i1 < iMaxDigit - iMyDigit; i1++) {
|
||
|
strcat(output, "0");
|
||
|
}
|
||
|
|
||
|
snprintf(cTemp, 128, "%d", rank);
|
||
|
strcat(output, cTemp);
|
||
|
}
|
||
|
}
|