Cloned SEACAS for EXODUS library with extra build files for internal package management.
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.

544 lines
19 KiB

2 years ago
/*
* Copyright(C) 1999-2020 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
*/
/*--------------------------------------------------------------------------*/
/* Purpose: Determine file types for command files and read in the parallel */
/* ExodusII command file. */
/*--------------------------------------------------------------------------*/
#include "copy_string_cpp.h"
#include "fmt/ostream.h"
#include "nem_spread.h"
#include "ps_pario_const.h" // for PIO_Info, Parallel_IO, etc
#include "rf_allo.h" // for array_alloc
#include "rf_io_const.h" // for ExoFile, etc
#include "scopeguard.h"
#include <cstdio> // for nullptr, stderr, etc
#include <cstdlib> // for exit, realloc
#include <cstring> // for strtok, strchr, strstr, etc
#include <rf_allo.h>
#define TLIST_CNT 5
constexpr int MAX_INPUT_STR_LN = 4096; /* maximum string length for read_string() */
/*****************************************************************************/
int read_mesh_file_name(const char *filename)
{
/* local declarations */
FILE *file_cmd = nullptr;
char inp_line[MAX_INPUT_STR_LN + 1];
char inp_copy[MAX_INPUT_STR_LN + 1];
/* Open the file */
if ((file_cmd = fopen(filename, "r")) == nullptr) {
return -1;
}
ON_BLOCK_EXIT(fclose, file_cmd);
/* Begin parsing the input file */
while (fgets(inp_line, MAX_INPUT_STR_LN, file_cmd) != nullptr) {
/* skip any line that is a comment */
if ((inp_line[0] != '#') && (inp_line[0] != '\n')) {
copy_string(inp_copy, inp_line);
clean_string(inp_line, " \t");
char *cptr = strtok(inp_line, "\t=");
/****** The input ExodusII file name ******/
if (token_compare(cptr, "input fem file") != 0) {
if (ExoFile.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
ExoFile = std::string(cptr);
break;
}
}
}
}
return 0;
}
/*****************************************************************************/
template <typename T, typename INT>
int read_pexoII_info(NemSpread<T, INT> &spreader, const char *filename)
/*
* This function reads the ASCII parallel-exodus command file.
*
* Input
* -----
* filename - The name of the command file.
*/
{
/* local declarations */
FILE *file_cmd = nullptr;
char inp_line[MAX_INPUT_STR_LN + 1];
char inp_copy[MAX_INPUT_STR_LN + 1];
char *cptr;
char *cptr2;
char *cptr3;
int i;
int icnt;
int tlist_alloc;
/***************************** BEGIN EXECUTION ******************************/
/* Open the file */
if ((file_cmd = fopen(filename, "r")) == nullptr) {
return -1;
}
ON_BLOCK_EXIT(fclose, file_cmd);
/* Begin parsing the input file */
while (fgets(inp_line, MAX_INPUT_STR_LN, file_cmd)) {
/* skip any line that is a comment */
if ((inp_line[0] != '#') && (inp_line[0] != '\n')) {
copy_string(inp_copy, inp_line);
clean_string(inp_line, " \t");
cptr = strtok(inp_line, "\t=");
/****** The input ExodusII file name ******/
if (token_compare(cptr, "input fem file")) {
if (ExoFile.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
ExoFile = std::string(cptr);
}
}
/****** The input NemesisI load balance file name ******/
else if (token_compare(cptr, "lb file")) {
if (Exo_LB_File.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
Exo_LB_File = std::string(cptr);
}
}
/****** The scalar results ExodusII file name ******/
else if (token_compare(cptr, "scalar results fem file")) {
if (Exo_Res_File.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
Exo_Res_File = std::string(cptr);
}
}
/****** The parallel results ExodusII file name ******/
else if (token_compare(cptr, "parallel results file base name")) {
if (Output_File_Base_Name.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
Output_File_Base_Name = std::string(cptr);
}
}
/****** The Number of Processors ******/
else if (token_compare(cptr, "number of processors")) {
if (spreader.Proc_Info[0] < 0) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
if (sscanf(cptr, "%d", &(spreader.Proc_Info[0])) != 1) {
fmt::print(stderr,
"{}: ERROR, can\'t interpret int for number of"
" Processors.\n",
__func__);
exit(1);
}
}
}
/****** The File extension to use for spread files ******/
else if (token_compare(cptr, "file extension for spread files")) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
PIO_Info.Exo_Extension = std::string(cptr);
}
/****** Is There a Scalar Mesh File to Use ******/
else if (token_compare(cptr, "use scalar mesh file")) {
if (Gen_Flag < 0) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
if (Gen_Flag < 0) {
if (token_compare(cptr, "yes")) {
Gen_Flag = 1;
}
else {
Gen_Flag = 0;
}
}
}
}
/****** The Debug reporting level ******/
else if (token_compare(cptr, "debug")) {
if (Debug_Flag < 0) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
if (sscanf(cptr, "%d", &Debug_Flag) != 1) {
fmt::print(stderr, "{}: ERROR, can\'t interpret int for Debug_Flag\n", __func__);
exit(1);
}
}
}
/****** Restart Time List ******/
else if (token_compare(cptr, "restart info")) {
cptr = strchr(cptr, '\0');
cptr++;
/*
* If there is a list, then need to change the comma's in
* the list to blank spaces so that the strtok below works
* correctly. So, search for commas between the beginning
* delimiter, "{", and the end delimiter, "}", and change
* them to blank spaces.
*/
cptr2 = strchr(cptr, '{');
if (cptr2 != nullptr) {
icnt = strlen(cptr2);
for (i = 0; i < icnt; i++) {
if (*cptr2 == '}') {
break;
}
if (*cptr2 == ',') {
*cptr2 = ' ';
}
cptr2++;
}
}
strip_string(cptr, " \t\n=");
cptr = strtok(cptr, ",");
/* Loop until all the suboptions have been specified */
while (cptr != nullptr) {
strip_string(cptr, " \t\n");
string_to_lower(cptr, '\0');
/* check if the user wants to specifically turn this off */
if (strcmp(cptr, "off") == 0) {
if (spreader.Restart_Info.Flag < 0) {
spreader.Restart_Info.Flag = 0;
spreader.Restart_Info.Num_Times = 0;
}
}
/* check if the user wants all of the time steps */
else if (strcmp(cptr, "all") == 0) {
if (spreader.Restart_Info.Flag < 0) {
spreader.Restart_Info.Flag = 1;
spreader.Restart_Info.Num_Times = -1; /* -1 designates read all times */
}
}
/* IGNORED check if the user wants move variable in blocks IGNORED */
else if (strstr(cptr, "block")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "fatal: must specify a value with \"block\"");
exit(1);
}
cptr2++;
}
/* check if the user has a list of time indices to get */
else if (strstr(cptr, "list")) {
/* "{" defines the beginning of the group designator */
cptr2 = strchr(cptr, '{');
if (cptr2 == nullptr) {
fmt::print(stderr, "fatal: list start designator \"{\" not found");
exit(1);
}
cptr2++;
cptr3 = strchr(cptr, '}');
if (cptr3 == nullptr) {
fmt::print(stderr, "fatal: list end designator \"}\" not found");
exit(1);
}
*cptr3 = '\0';
/* Allocate the time list */
spreader.Restart_Info.Time_Idx.resize(TLIST_CNT);
tlist_alloc = TLIST_CNT;
spreader.Restart_Info.Num_Times = 0;
while (cptr2) {
/* first check to see if they want to get the last time index */
if (strncmp(cptr2, "last", 4) == 0) {
icnt = 0;
spreader.Restart_Info.Time_Idx[spreader.Restart_Info.Num_Times] = 0;
}
else {
icnt = sscanf(cptr2, "%d",
&(spreader.Restart_Info.Time_Idx[spreader.Restart_Info.Num_Times]));
}
if (icnt >= 0) {
(spreader.Restart_Info.Num_Times)++;
}
if (spreader.Restart_Info.Num_Times >= tlist_alloc) {
tlist_alloc += TLIST_CNT;
spreader.Restart_Info.Time_Idx.resize(tlist_alloc);
}
/* move to the next blank space */
cptr3 = strchr(cptr2, ' ');
if (cptr3) {
/* find the next non-blank space */
while (*cptr3 == ' ') {
cptr3++;
}
}
cptr2 = cptr3;
}
}
else {
fmt::print(stderr, "warning: unknown restart info suboption {}", cptr);
exit(1);
}
cptr = strtok(nullptr, ",");
}
} /* End "if (token_compare(cptr, "restart time list"))" */
/****** Reserved Space for Variables ******/
else if (token_compare(cptr, "reserve space")) {
cptr = strchr(cptr, '\0');
cptr++;
strip_string(cptr, " \t\n=");
cptr = strtok(cptr, ",");
while (cptr != nullptr) {
strip_string(cptr, " \t\n");
string_to_lower(cptr, '=');
if (strstr(cptr, "nodal")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: integer value must be specified for"
" reserve space.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &Num_Nod_Var);
if ((icnt <= 0) || (Num_Nod_Var < 0)) {
fmt::print(stderr, "Error: Invalid value for nodal variable\n");
return 0;
}
}
else if (strstr(cptr, "elemental")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: integer value must be specified for"
" reserve space.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &Num_Elem_Var);
if ((icnt <= 0) || (Num_Elem_Var < 0)) {
fmt::print(stderr, "Error: Invalid value for elemental variable\n");
return 0;
}
}
else if (strstr(cptr, "global")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: integer value must be specified for"
" reserve space.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &Num_Glob_Var);
if ((icnt <= 0) || (Num_Glob_Var < 0)) {
fmt::print(stderr, "Error: Invalid value for global variable\n");
return 0;
}
}
else if (strstr(cptr, "nodeset")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: integer value must be specified for"
" reserve space.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &Num_Nset_Var);
if ((icnt <= 0) || (Num_Nset_Var < 0)) {
fmt::print(stderr, "Error: Invalid value for nodeset variable\n");
return 0;
}
}
else if (strstr(cptr, "sideset")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: integer value must be specified for"
" reserve space.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &Num_Sset_Var);
if ((icnt <= 0) || (Num_Sset_Var < 0)) {
fmt::print(stderr, "Error: Invalid value for sideset variable\n");
return 0;
}
}
cptr = strtok(nullptr, ",");
} /* End "while (cptr != nullptr)" */
} /* End "else if (token_compare(cptr, "reserve space"))" */
/****** Parallel Disk Information ******/
else if (token_compare(cptr, "parallel disk info")) {
cptr = strchr(cptr, '\0');
cptr++;
strip_string(cptr, " \t\n=");
cptr = strtok(cptr, ",");
strip_string(cptr, " \t\n");
string_to_lower(cptr, '=');
/* the first sub-option must be "number" */
if (!strstr(cptr, "number")) {
fmt::print(stderr, "Error: First sup-option for disk info must be "
"\"number\"\n");
return 0;
}
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: integer value must be specified for"
" reserve space.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &(PIO_Info.Num_Dsk_Ctrlrs));
if ((icnt <= 0) || (PIO_Info.Num_Dsk_Ctrlrs <= 0)) {
fmt::print(stderr, "Error: Invalid value for # of raid controllers\n");
return 0;
}
cptr = strtok(nullptr, ",");
while (cptr != nullptr) {
strip_string(cptr, " \t\n");
string_to_lower(cptr, '=');
if (strstr(cptr, "list")) {
/*
* So, "number" references the length of the list, and
* I need to do some shuffling to make the new form
* work with the old code.
*/
PIO_Info.Dsk_List_Cnt = PIO_Info.Num_Dsk_Ctrlrs;
PIO_Info.Num_Dsk_Ctrlrs = 0;
/* "{" defines the beginning of the list */
cptr = strchr(cptr, '{');
if (cptr == nullptr) {
fmt::print(stderr, "Error: disk list must be specified\n");
return 0;
}
cptr++;
/* allocate memory for to hold the values */
PIO_Info.Dsk_List = reinterpret_cast<int *>(
array_alloc(__FILE__, __LINE__, 1, PIO_Info.Dsk_List_Cnt, sizeof(int)));
for (i = 0; i < (PIO_Info.Dsk_List_Cnt - 1); i++) {
sscanf(cptr, "%d", &(PIO_Info.Dsk_List[i]));
cptr = strtok(nullptr, ", \t;");
}
/* last one is a special case */
sscanf(cptr, "%d}", &(PIO_Info.Dsk_List[i]));
}
else if (strstr(cptr, "offset")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "Error: value must be specified with the "
"\"offset\" option.\n");
return 0;
}
cptr2++;
icnt = sscanf(cptr2, "%d", &(PIO_Info.PDsk_Add_Fact));
if ((icnt <= 0) || (PIO_Info.PDsk_Add_Fact < 0)) {
fmt::print(stderr, "Error: Invalid value for offset\n");
return 0;
}
}
else if (strstr(cptr, "zeros")) {
PIO_Info.Zeros = 1;
}
else if (strstr(cptr, "nosubdirectory")) {
PIO_Info.NoSubdirectory = 1;
}
else if (strstr(cptr, "stage_off")) {
PIO_Info.Staged_Writes = false;
}
else if (strstr(cptr, "stage_on")) {
PIO_Info.Staged_Writes = true;
}
cptr = strtok(nullptr, ",");
}
} /* End "else if (token_compare(cptr, "parallel disk info"))" */
else if (token_compare(cptr, "parallel file location")) {
cptr = strchr(cptr, '\0');
cptr++;
strip_string(cptr, " \t\n=");
cptr = strtok(cptr, ",");
while (cptr != nullptr) {
strip_string(cptr, " \t\n");
string_to_lower(cptr, '=');
if (strstr(cptr, "root")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "fatal: must specify a path with \"root\"");
return 0;
}
cptr2++;
if (strlen(cptr2) == 0) {
fmt::print(stderr, "fatal: invalid path name specified with"
" \"root\"");
return 0;
}
PIO_Info.Par_Dsk_Root = std::string(cptr2);
}
if (strstr(cptr, "subdir")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
fmt::print(stderr, "fatal: must specify a path with \"subdir\"");
return 0;
}
cptr2++;
if (strlen(cptr2) == 0) {
fmt::print(stderr, "fatal: invalid path name specified with"
" \"subdir\"");
return 0;
}
PIO_Info.Par_Dsk_SubDirec = std::string(cptr2);
if (PIO_Info.Par_Dsk_SubDirec.back() != '/') {
PIO_Info.Par_Dsk_SubDirec += '/';
}
}
cptr = strtok(nullptr, ",");
}
}
} /* End "if(inp_line[0] != '#')" */
} /* End "while(fgets(inp_line, MAX_INPUT_STR_LN, file_cmd))" */
if (Output_File_Base_Name.empty() && !Exo_LB_File.empty()) {
// User did not specify a base name. Use the basenmae of the
// Exo_LB_File instead.
Output_File_Base_Name = Exo_LB_File;
// If there is an extension, strip it off...
size_t found = Output_File_Base_Name.find_last_of('.');
if (found != std::string::npos) {
Output_File_Base_Name = Output_File_Base_Name.substr(0, found);
}
}
return 0;
}
template int read_pexoII_info(NemSpread<float, int> &spreader, const char *filename);
template int read_pexoII_info(NemSpread<double, int> &spreader, const char *filename);
template int read_pexoII_info(NemSpread<double, int64_t> &spreader, const char *filename);
template int read_pexoII_info(NemSpread<float, int64_t> &spreader, const char *filename);