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.

1816 lines
60 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
*/
/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
*----------------------------------------------------------------------------
* Functions contained in this file:
* cmd_line_arg_parse()
* read_cmd_file()
* check_inp_specs()
*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
#include "copy_string_cpp.h"
#include "elb.h" // for Problem_Description, etc
#include "elb_err.h" // for Gen_Error, error_lev
#include "elb_inp.h"
#include "elb_util.h" // for strip_string, token_compare, etc
#include "fmt/ostream.h"
#if defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || \
defined(__MINGW32__) || defined(_WIN64) || defined(__MINGW64__)
#include "XGetopt.h"
#include <unistd.h>
#else
#include "getopt.h" // for getopt
#endif
#include "scopeguard.h"
#include <cstddef> // for size_t
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 500
#endif
#include <cstdlib> // for malloc, exit, free
#include <cstring> // for strcmp, strstr, strchr, etc
#include <exodusII.h> // for ex_close, EX_READ, etc
namespace {
int my_getsubopt(char **optionp, char *const *tokens, char **valuep);
void print_usage();
std::string remove_extension(const std::string &filename)
{
// Strip off the extension
size_t ind = filename.find_last_of('.', filename.size());
if (ind != std::string::npos) {
return filename.substr(0, ind);
}
return filename;
}
} // namespace
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* This function parses the command line options and stores the information
* in the appropriate data locations.
*---------------------------------------------------------------------------*/
template int cmd_line_arg_parse(int argc, char *argv[], std::string &exoII_inp_file,
std::string &ascii_inp_file, std::string &nemI_out_file,
Machine_Description *machine, LB_Description<int> *lb,
Problem_Description *prob, Solver_Description *solver,
Weight_Description<int> *weight);
template int cmd_line_arg_parse(int argc, char *argv[], std::string &exoII_inp_file,
std::string &ascii_inp_file, std::string &nemI_out_file,
Machine_Description *machine, LB_Description<int64_t> *lb,
Problem_Description *prob, Solver_Description *solver,
Weight_Description<int64_t> *weight);
template <typename INT>
int cmd_line_arg_parse(int argc, char *argv[], /* Args as passed by main() */
std::string &exoII_inp_file, /* The input ExodusII file name */
std::string &ascii_inp_file, /* The ASCII input file name */
std::string &nemI_out_file, /* Output NemesisI file name */
Machine_Description *machine, /* Structure for machine description */
LB_Description<INT> *lb, /* Structure for load balance description */
Problem_Description *prob, /* Structure for various problem params */
Solver_Description *solver, /* Structure for eigen solver params */
Weight_Description<INT> *weight /* Structure for weighting graph */
)
{
int opt_let;
int iret;
int el_blk;
int wgt;
int max_dim = 0;
int i;
char *sub_opt = nullptr, *value = nullptr, *cptr = nullptr, *cptr2 = nullptr;
std::string ctemp;
/* see NOTE in elb.h about the order of the following array */
const char *weight_subopts[] = {"none", "read", "eb", "var_index",
"edges", "time_index", "var_name", nullptr};
const char *mach_subopts[] = {"mesh", "hcube", "hypercube", "cluster", nullptr};
const char *lb_subopts[] = {"multikl", "spectral", "inertial", "linear", "random",
"scattered", "infile", "kl", "none", "num_sects",
"cnctd_dom", "outfile", "zpinch", "brick", "rcb",
"rib", "hsfc", "ignore_z", nullptr};
const char *solve_subopts[] = {"tolerance", "use_rqi", "vmax", nullptr};
/*---------------------------Execution Begins--------------------------------*/
/*
* Make sure there were command line options given. If not assign the
* name of the default ascii input file.
*/
if (argc <= 1) {
print_usage();
exit(0);
}
/* Loop over each command line option */
while ((opt_let = getopt(argc, argv, "3264a:hm:l:nes:x:w:vyo:cg:fpS")) != EOF) {
/* case over the option letter */
switch (opt_let) {
case 'v':
/* Should an output visualization file be output */
prob->vis_out = 1;
break;
case 'y':
/* Should an output visualization file be output */
prob->vis_out = 2;
break;
case 'x':
/* Undocumented flag for setting the error level */
if (optarg == nullptr) {
error_lev = 1;
}
else {
iret = sscanf(optarg, "%d", &error_lev);
if (iret != 1) {
error_lev = 1;
}
if (error_lev > 3) {
error_lev = 3;
}
}
break;
case 'c':
/* flag to allow the user to skip some error checks */
prob->skip_checks = 1;
break;
case 'f':
/*
* use the face method to calculate adjacencies for
* elemental decompositions
*/
prob->face_adj = 1;
break;
case 'C':
/*
* detect vertical columns of elements and ensure that
* elements of a columns are all in one partition
*/
prob->fix_columns = 1;
break;
case 'p':
/*
* use the partial method to determine adjacencies:
* only 3/4 of face nodes must match instead of all
*/
prob->partial_adj = 1;
break;
case 'w':
/* Weighting options */
sub_opt = optarg;
while (sub_opt != nullptr && *sub_opt != '\0') {
switch (my_getsubopt(&sub_opt, (char *const *)weight_subopts, &value)) {
case READ_EXO:
if (value == nullptr || strlen(value) == 0) {
ctemp =
fmt::format("FATAL: must specify a file name with {}", weight_subopts[READ_EXO]);
Gen_Error(0, ctemp);
return 0;
}
if (weight->type < 0) {
weight->type = READ_EXO;
}
else if (!(weight->type & READ_EXO)) {
weight->type += READ_EXO;
}
/* check if the read is after an element block weight */
if (weight->type & EL_BLK) {
weight->ow_read = 0;
}
weight->exo_filename = value;
break; /* End "case READ_EXO" */
case VAR_INDX:
if (value == nullptr || strlen(value) == 0) {
ctemp = fmt::format("FATAL: must specify a value with {}", weight_subopts[VAR_INDX]);
Gen_Error(0, ctemp);
return 0;
}
iret = sscanf(value, "%d", &(weight->exo_vindx));
if (iret != 1) {
ctemp = fmt::format("FATAL: invalid value specified for {}", weight_subopts[VAR_INDX]);
Gen_Error(0, ctemp);
return 0;
}
break;
case TIME_INDX:
if (value == nullptr || strlen(value) == 0) {
ctemp = fmt::format("FATAL: must specify a value with {}", weight_subopts[TIME_INDX]);
Gen_Error(0, ctemp);
return 0;
}
iret = sscanf(value, "%d", &(weight->exo_tindx));
if (iret != 1) {
ctemp = fmt::format("FATAL: invalid value specified for {}", weight_subopts[TIME_INDX]);
Gen_Error(0, ctemp);
return 0;
}
break;
case VAR_NAME:
if (value == nullptr || strlen(value) == 0) {
ctemp = fmt::format("FATAL: must specify a value with {}", weight_subopts[VAR_NAME]);
Gen_Error(0, ctemp);
return 0;
}
weight->exo_varname = value;
break;
case EL_BLK:
if (value == nullptr) {
ctemp = fmt::format("FATAL: must specify an element block and weight with {}",
weight_subopts[EL_BLK]);
Gen_Error(0, ctemp);
return 0;
}
el_blk = -1;
wgt = -1;
iret = sscanf(value, "%d:%d", &el_blk, &wgt);
if (iret != 2) {
Gen_Error(0, "invalid element block weight");
return 0;
}
if (el_blk <= 0) {
ctemp = fmt::format("invalid element block, %d", el_blk);
Gen_Error(0, ctemp);
return 0;
}
if (wgt < 0) {
ctemp = fmt::format("invalid weight, %d", wgt);
Gen_Error(0, ctemp);
return 0;
}
weight->elemblk.push_back(el_blk);
weight->elemblk_wgt.push_back(wgt);
if (weight->type < 0) {
weight->type = EL_BLK;
}
else if (!(weight->type & EL_BLK)) {
weight->type += EL_BLK;
}
/* check if the element block weight needs to over write the read */
if (weight->type & READ_EXO) {
weight->ow_read = 1;
}
break;
case EDGE_WGT:
if (weight->type < 0) {
weight->type = EDGE_WGT;
}
else if (!(weight->type & EDGE_WGT)) {
weight->type += EDGE_WGT;
}
break;
case NO_WEIGHT: weight->type = NO_WEIGHT; break;
default:
ctemp = fmt::format("FATAL: unknown suboption {} specified", value);
Gen_Error(0, ctemp);
return 0;
} /* End "switch(my_getsubopt(&sub_opt, weight_subopts, &value))" */
} /* End "while(*sub_opt != '\0')" */
break; /* End "case 'w'" */
case 'a':
/* Only an ASCII input file name */
if (optarg != nullptr) {
ascii_inp_file = optarg;
}
break;
case 'o':
/* Output NemesisI file name */
if (optarg != nullptr) {
nemI_out_file = optarg;
}
break;
case 'n':
/* Nodal decomposition */
if (prob->type == ELEMENTAL) {
Gen_Error(0, "FATAL: -e and -n are mutually exclusive");
return 0;
}
prob->type = NODAL;
break;
case 'e':
/* Elemental decomposition */
if (prob->type == NODAL) {
Gen_Error(0, "FATAL: -e and -n are mutually exclusive\n");
return 0;
}
prob->type = ELEMENTAL;
break;
case 'm':
/* Machine type */
sub_opt = optarg;
if (sub_opt != nullptr) {
string_to_lower(sub_opt, '\0');
}
while (sub_opt != nullptr && *sub_opt != '\0') {
/* Switch over the machine description */
switch (my_getsubopt(&sub_opt, (char *const *)mach_subopts, &value)) {
case HCUBE:
case HYPERCUBE:
if (machine->type < 0) {
machine->type = HCUBE;
max_dim = 1;
}
FALL_THROUGH;
case MESH:
if (machine->type < 0) {
machine->type = MESH;
max_dim = 3;
}
cptr = value; /* want to set this for both mesh and hcube */
FALL_THROUGH;
case CLUSTER:
if (machine->type < 0) /* so, get the number of boxes */
{
if (value == nullptr || strlen(value) == 0) {
Gen_Error(0, "FATAL: need to specify number of boxes");
return 0;
}
/* now need to find what each box consists of */
cptr = strpbrk(value, "mMhH");
if (*cptr == 'm' || *cptr == 'M') {
machine->type = MESH;
max_dim = 3;
}
else if (*cptr == 'h' || *cptr == 'H') {
machine->type = HCUBE;
max_dim = 1;
}
else {
Gen_Error(0, "FATAL: unknown type specified with cluster");
return 0;
}
/* blank out character and move cptr to next char */
*cptr = '\0';
cptr++;
/* get the number of boxes from value */
iret = sscanf(value, "%d", &(machine->num_boxes));
if (iret <= 0 || machine->num_boxes <= 0) {
Gen_Error(0, "FATAL: invalid number of boxes");
return 0;
}
}
if (cptr == nullptr || strlen(cptr) == 0) {
Gen_Error(0, "FATAL: need to specify dimension");
return 0;
}
cptr2 = strtok(cptr, "xX");
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: bad size for dimension specification");
return 0;
}
machine->num_dims = 0;
for (i = 0; i < max_dim; i++) {
machine->dim[i] = 1;
}
while (cptr2) {
iret = sscanf(cptr2, "%d", &(machine->dim[machine->num_dims]));
if (iret <= 0 || machine->dim[machine->num_dims] <= 0) {
Gen_Error(0, "FATAL: invalid dimension specification");
return 0;
}
machine->num_dims++;
cptr2 = strtok(nullptr, "xX");
/* Only up to three-dimensional allowed */
if (machine->num_dims == max_dim && cptr2 != nullptr) {
Gen_Error(0, "FATAL: maximum number of dimensions exceeded");
return 0;
}
}
break; /* End "case MESH or HCUBE or CLUSTER" */
default: Gen_Error(0, "FATAL: unknown machine type"); return 0;
} /* End "switch(my_getsubopt(&sub_opt, mach_subopts, &value))" */
} /* End "while(*sub_opt != '\0')" */
break; /* End "case 'm'" */
case 'l':
/* Load balance information */
sub_opt = optarg;
if (sub_opt != nullptr) {
string_to_lower(sub_opt, '\0');
}
while (sub_opt != nullptr && *sub_opt != '\0') {
switch (my_getsubopt(&sub_opt, (char *const *)lb_subopts, &value)) {
case MULTIKL: lb->type = MULTIKL; break;
case SPECTRAL: lb->type = SPECTRAL; break;
case INERTIAL: lb->type = INERTIAL; break;
case ZPINCH: lb->type = ZPINCH; break;
case BRICK: lb->type = BRICK; break;
case ZOLTAN_RCB: lb->type = ZOLTAN_RCB; break;
case ZOLTAN_RIB: lb->type = ZOLTAN_RIB; break;
case ZOLTAN_HSFC: lb->type = ZOLTAN_HSFC; break;
case LINEAR: lb->type = LINEAR; break;
case RANDOM: lb->type = RANDOM; break;
case SCATTERED: lb->type = SCATTERED; break;
case INFILE:
if (value == nullptr) {
Gen_Error(0, "FATAL: need to specify a value with file");
return 0;
}
char tmpstr[2048];
iret = sscanf(value, "%2047s", tmpstr);
lb->file = tmpstr;
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value associated with file");
return 0;
}
lb->type = INFILE;
break;
case KL_REFINE: lb->refine = KL_REFINE; break;
case NO_REFINE: lb->refine = NO_REFINE; break;
case NUM_SECTS:
if (value == nullptr) {
Gen_Error(0, "FATAL: need to specify a value with num_sects");
return 0;
}
iret = sscanf(value, "%d", &(lb->num_sects));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value associated with num_sects");
return 0;
}
break;
case CNCT_DOM: lb->cnctd_dom = 1; break;
case IGNORE_Z: lb->ignore_z = 1; break;
case OUTFILE:
if (value == nullptr) {
Gen_Error(0, "FATAL: need to specify a value with outfile");
return 0;
}
iret = sscanf(value, "%2047s", tmpstr);
lb->file = tmpstr;
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value associated with outfile");
return 0;
}
lb->outfile = ELB_TRUE;
break;
default:
ctemp = fmt::format("FATAL: unknown lb param \"{}\"", value);
Gen_Error(0, ctemp);
return 0;
} /* End "switch(my_getsubopt(&sup_opt, mach_subopts, &value))" */
} /* End "while(*sup_opt != '\0')" */
break; /* End "case 'l'" */
case 'S': prob->no_sph = 1; break;
case 's':
/* Eigen solver options */
sub_opt = optarg;
if (sub_opt != nullptr) {
string_to_lower(sub_opt, '\0');
}
while (sub_opt != nullptr && *sub_opt != '\0') {
switch (my_getsubopt(&sub_opt, (char *const *)solve_subopts, &value)) {
case TOLER:
if (value == nullptr) {
fmt::print(stderr, "FATAL: tolerance specification requires \
value\n");
return 0;
}
iret = sscanf(value, "%le", &(solver->tolerance));
if (iret != 1) {
fmt::print(stderr, "FATAL: incorrect value for tolerance\n");
return 0;
}
break;
case USE_RQI:
if (solver->rqi_flag == USE_RQI) {
solver->rqi_flag = -1;
}
else {
solver->rqi_flag = USE_RQI;
}
break;
case VMAX:
if (value == nullptr) {
fmt::print(stderr, "FATAL: must specify a value with {}\n", solve_subopts[VMAX]);
return 0;
}
iret = sscanf(value, "%d", &(solver->vmax));
if (iret != 1) {
fmt::print(stderr, "FATAL: invalid value read for {}\n", solve_subopts[VMAX]);
return 0;
}
break;
default: fmt::print(stderr, "FATAL: unknown solver option\n"); return 0;
} /* End "switch(my_getsubopt(&sub_opt, solve_subopts, &value))" */
} /* End "while(sub_opt != '\0')" */
break; /* End "case 's'" */
case 'g':
/* group designations */
/* allocate string to hold designation */
if (optarg != nullptr) {
prob->groups = reinterpret_cast<char *>(malloc(strlen(optarg) + 1));
copy_string(prob->groups, optarg, strlen(optarg) + 1);
}
break;
case 'h':
/* Usage info was requested */
print_usage();
exit(0);
case '6':
case '4':
/* ignore -- used to parse -64 option */
break;
case '3':
case '2':
/* ignore -- used to parse -32 option */
break;
default:
/* Default case. Error on unknown argument. */
return 0;
} /* End "switch(opt_let)" */
} /* End "while((opt_let=getopt(argc, argv, "i")) != EOF)" */
/* Get the input file name, if specified on the command line */
if ((argc - optind) >= 1) {
exoII_inp_file = argv[optind];
}
else {
exoII_inp_file = "";
}
return 1;
} /*-------End cmd_line_arg_parse()--------*/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* This function reads in the ASCII command file.
*---------------------------------------------------------------------------*/
template int read_cmd_file(std::string &ascii_inp_file, std::string &exoII_inp_file,
std::string &nemI_out_file, Machine_Description *machine,
LB_Description<int> *lb, Problem_Description *problem,
Solver_Description *solver, Weight_Description<int> *weight);
template int read_cmd_file(std::string &ascii_inp_file, std::string &exoII_inp_file,
std::string &nemI_out_file, Machine_Description *machine,
LB_Description<int64_t> *lb, Problem_Description *problem,
Solver_Description *solver, Weight_Description<int64_t> *weight);
template <typename INT>
int read_cmd_file(std::string &ascii_inp_file, std::string &exoII_inp_file,
std::string &nemI_out_file, Machine_Description *machine, LB_Description<INT> *lb,
Problem_Description *problem, Solver_Description *solver,
Weight_Description<INT> *weight)
{
FILE *inp_fd;
std::string ctemp;
char inp_line[MAX_INP_LINE];
char inp_copy[MAX_INP_LINE];
char *cptr, *cptr2;
int iret;
int el_blk;
int wgt;
int i;
int ilen;
int max_dim;
char tmpstr[2048];
/*-----------------------------Execution Begins------------------------------*/
if (!(inp_fd = fopen(ascii_inp_file.c_str(), "r"))) {
ctemp = fmt::format("FATAL: unable to open ASCII input file {}", ascii_inp_file);
Gen_Error(0, ctemp);
return 0;
}
ON_BLOCK_EXIT(fclose, inp_fd);
/* Begin parsing the input file */
while (fgets(inp_line, MAX_INP_LINE, inp_fd)) {
if (inp_line[0] != '#') {
copy_string(inp_copy, inp_line);
clean_string(inp_line, " \t");
cptr = strtok(inp_line, "\t=");
if (token_compare(cptr, "input exodusii file")) {
/* The input ExodusII file name */
if (exoII_inp_file.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
exoII_inp_file = cptr;
}
}
else if (token_compare(cptr, "output visualization file")) {
if (problem->vis_out < 0) {
/* Output a visualization file */
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
if (strcasecmp(cptr, "yes") == 0 || strcasecmp(cptr, "true") == 0) {
problem->vis_out = 1;
}
else if (strcasecmp(cptr, "no") == 0 || strcasecmp(cptr, "false") == 0) {
problem->vis_out = 0;
}
else {
iret = sscanf(cptr, "%d", &problem->vis_out);
if (iret != 1) {
Gen_Error(1, "WARNING: unknown visualization output flag");
problem->vis_out = 0;
}
else {
if (problem->vis_out != 1 && problem->vis_out != 2) {
problem->vis_out = 0;
}
}
}
}
}
else if (token_compare(cptr, "output nemesisi file")) {
/* The NemesisI output file name */
if (nemI_out_file.empty()) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
nemI_out_file = cptr;
}
}
else if (token_compare(cptr, "decomposition method")) {
/* The method to use for decomposing the graph */
if (lb->type < 0 || lb->refine < 0 || lb->num_sects < 0) {
/* Search to the first null character */
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, '\0');
if (strcmp(cptr, "multikl") == 0) {
if (lb->type < 0) {
lb->type = MULTIKL;
}
}
else if (strcmp(cptr, "spectral") == 0) {
if (lb->type < 0) {
lb->type = SPECTRAL;
}
}
else if (strcmp(cptr, "scattered") == 0) {
if (lb->type < 0) {
lb->type = SCATTERED;
}
}
else if (strcmp(cptr, "linear") == 0) {
if (lb->type < 0) {
lb->type = LINEAR;
}
}
else if (strcmp(cptr, "inertial") == 0) {
if (lb->type < 0) {
lb->type = INERTIAL;
}
}
else if (strcmp(cptr, "zpinch") == 0) {
if (lb->type < 0) {
lb->type = ZPINCH;
}
}
else if (strcmp(cptr, "brick") == 0) {
if (lb->type < 0) {
lb->type = BRICK;
}
}
else if (strcmp(cptr, "rcb") == 0) {
if (lb->type < 0) {
lb->type = ZOLTAN_RCB;
}
}
else if (strcmp(cptr, "rib") == 0) {
if (lb->type < 0) {
lb->type = ZOLTAN_RIB;
}
}
else if (strcmp(cptr, "hsfc") == 0) {
if (lb->type < 0) {
lb->type = ZOLTAN_HSFC;
}
}
else if (strcmp(cptr, "random") == 0) {
if (lb->type < 0) {
lb->type = RANDOM;
}
}
else if (strstr(cptr, "infile")) {
if (lb->type < 0) {
lb->type = INFILE;
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: need to specify a value with infile");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%2047s", tmpstr);
lb->file = tmpstr;
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value for infile");
return 0;
}
}
}
else if (strcmp(cptr, "kl") == 0) {
if (lb->refine < 0) {
lb->refine = KL_REFINE;
}
}
else if (strcmp(cptr, "none") == 0) {
if (lb->refine < 0) {
lb->refine = NS_NONE;
}
}
else if (strcmp(cptr, "ignore_z") == 0) {
lb->ignore_z = 1;
}
else if (strstr(cptr, "num_sects")) {
if (lb->num_sects < 0) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: need to specify a value with num_sects");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%d", &(lb->num_sects));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value for num_sects");
return 0;
}
}
}
else if (strcmp(cptr, "cnctd_dom") == 0) {
if (lb->cnctd_dom < 0) {
lb->cnctd_dom = ELB_TRUE;
}
}
else if (strstr(cptr, "outfile")) {
if (lb->outfile < 0) {
lb->outfile = ELB_TRUE;
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: need to specify a value with outfile");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%2047s", tmpstr);
lb->file = tmpstr;
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value for outfile");
return 0;
}
}
}
else {
ctemp =
fmt::format("FATAL: unknown LB method \"{}\" specified in command file", cptr);
Gen_Error(0, ctemp);
return 0;
}
cptr = strtok(nullptr, ",");
}
}
}
else if (token_compare(cptr, "solver specifications")) {
/* Solver specs */
/* Search to the first null character */
cptr = strchr(cptr, '\0');
cptr++;
strip_string(cptr, " \t\n=");
cptr = strtok(cptr, ",");
/* Loop until all the suboptions have been specified */
while (cptr) {
strip_string(cptr, " \t\n");
string_to_lower(cptr, '\0');
/* Check to see if this is the "tolerance" suboption */
if (strstr(cptr, "tolerance")) {
if (solver->tolerance < 0.0) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: tolerance specification requires a value");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%le", &(solver->tolerance));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value for tolerance");
return 0;
}
}
}
else if (strcmp(cptr, "use_rqi") == 0) {
if (solver->rqi_flag == USE_RQI) {
solver->rqi_flag = -1;
}
else {
solver->rqi_flag = USE_RQI;
}
}
else if (strstr(cptr, "vmax")) {
if (solver->vmax < 0) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: vmax must have a value");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%d", &(solver->vmax));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value for vmax");
return 0;
}
}
}
else {
ctemp = fmt::format("WARNING: unknown solver suboption {}", cptr);
Gen_Error(1, ctemp);
}
cptr = strtok(nullptr, ",");
}
}
else if (token_compare(cptr, "graph type")) {
if (problem->type < 0) {
cptr = strtok(nullptr, "\t=");
strip_string(cptr, " \t\n");
string_to_lower(cptr, '\0');
if (strcmp(cptr, "nodal") == 0) {
problem->type = NODAL;
}
else if (strcmp(cptr, "node") == 0) {
problem->type = NODAL;
}
else if (strcmp(cptr, "elemental") == 0) {
problem->type = ELEMENTAL;
}
else if (strcmp(cptr, "element") == 0) {
problem->type = ELEMENTAL;
}
else {
Gen_Error(0, "FATAL: unknown graph type specified");
return 0;
}
}
}
else if (token_compare(cptr, "machine description")) {
/* Machine specs */
if (machine->num_dims < 0) {
/* Search to first null character */
cptr = strchr(cptr, '\0');
cptr++;
strip_string(cptr, " \t\n=");
/* Search to equal sign */
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: machine must have a dimension specified");
return 0;
}
*cptr2 = '\0';
/* Find out the machine type */
strip_string(cptr, " \t\n");
if (strcasecmp(cptr, "mesh") == 0) {
machine->type = MESH;
max_dim = 3;
}
else if (strcasecmp(cptr, "hcube") == 0 || strcasecmp(cptr, "hypercube") == 0) {
machine->type = HCUBE;
max_dim = 1;
}
else if (strcasecmp(cptr, "cluster") == 0) {
/* now need to find what each box consists of */
cptr = cptr2 + 1;
cptr2 = strpbrk(cptr, "mMhH");
if (*cptr2 == 'm' || *cptr2 == 'M') {
machine->type = MESH;
max_dim = 3;
}
else if (*cptr2 == 'h' || *cptr2 == 'H') {
machine->type = HCUBE;
max_dim = 1;
}
else {
Gen_Error(0, "FATAL: unknown type specified with cluster");
return 0;
}
/* blank out character and move cptr to next char */
*cptr2 = '\0';
/* get the number of boxes from value */
iret = sscanf(cptr, "%d", &(machine->num_boxes));
if (iret <= 0 || machine->num_boxes <= 0) {
Gen_Error(0, "FATAL: invalid number of boxes");
return 0;
}
}
else {
Gen_Error(0, "FATAL: unknown machine type specified");
return 0;
}
machine->num_dims = 0;
cptr = cptr2 + 1;
cptr = strtok(cptr, "xX");
while (cptr) {
iret = sscanf(cptr, "%d", &(machine->dim[machine->num_dims]));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid dimension specified for machine");
return 0;
}
machine->num_dims++;
cptr = strtok(nullptr, "xX");
/* Check how many dimensions there are */
if (machine->num_dims == max_dim && cptr != nullptr) {
Gen_Error(0, "FATAL: maximum number of dimensions exceeded");
return 0;
}
}
}
}
else if (token_compare(cptr, "weighting specifications")) {
/* Parameters for weighting the graph */
if (weight->type < 0) {
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, '\0');
if (strstr(cptr, "read")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: must specify file name with \"read\"");
return 0;
}
cptr2++;
if (strlen(cptr2) == 0) {
Gen_Error(0, "FATAL: invalid file name with \"read\"");
return 0;
}
weight->exo_filename = cptr2;
if (weight->type < 0) {
weight->type = READ_EXO;
}
else if (!(weight->type & READ_EXO)) {
weight->type += READ_EXO;
}
/* check if the read is after an element block weight */
if (weight->type & EL_BLK) {
weight->ow_read = 0;
}
}
else if (strstr(cptr, "var_name")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: must specify a name with \"var_name\"");
return 0;
}
cptr2++;
if (strlen(cptr2) == 0) {
Gen_Error(0, "FATAL: invalid variable name specified with"
" \"var_name\"");
return 0;
}
weight->exo_varname = cptr2;
}
else if (strstr(cptr, "var_index")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: must specify a value with \"var_index\"");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%d", &(weight->exo_vindx));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value with \"var_index\"");
return 0;
}
}
else if (strstr(cptr, "time_index")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: must specify a value with \"time_index\"");
return 0;
}
cptr2++;
iret = sscanf(cptr2, "%d", &(weight->exo_tindx));
if (iret != 1) {
Gen_Error(0, "FATAL: invalid value with \"time_index\"");
return 0;
}
}
else if (strstr(cptr, "eb")) {
cptr2 = strchr(cptr, '=');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: must specify a value with \"eb\"");
return 0;
}
cptr2++;
el_blk = -1;
wgt = -1;
iret = sscanf(cptr2, "%d:%d", &el_blk, &wgt);
if (iret != 2) {
Gen_Error(0, "FATAL: invalid value with \"eb\"");
return 0;
}
if (el_blk <= 0) {
ctemp = fmt::format("invalid element block, %d", el_blk);
Gen_Error(0, ctemp);
return 0;
}
if (wgt < 1) {
ctemp = fmt::format("invalid weight, %d", wgt);
Gen_Error(0, ctemp);
return 0;
}
if (weight->type < 0) {
weight->type = EL_BLK;
}
else if (!(weight->type & EL_BLK)) {
weight->type += EL_BLK;
}
weight->elemblk.push_back(el_blk);
weight->elemblk_wgt.push_back(wgt);
/* check if the elem block weight needs to overwrite the read */
if (weight->type & READ_EXO) {
weight->ow_read = 1;
}
}
else if (strstr(cptr, "edges")) {
if (weight->type < 0) {
weight->type = EDGE_WGT;
}
else if (!(weight->type & EDGE_WGT)) {
weight->type += EDGE_WGT;
}
}
else {
ctemp = fmt::format("FATAL: unknown suboption \"{}\" specified", cptr);
Gen_Error(0, ctemp);
return 0;
}
cptr = strtok(nullptr, ",");
}
} /* End "if(weight->type < 0)" */
}
else if (token_compare(cptr, "misc options")) {
/* Misc Options */
/* Search to the first null character */
cptr = strchr(cptr, '\0');
cptr++;
/*
* Need to handle case where users have put comma's in
* the group descriptor. This will mess up getting the
* tokens using strtok(). So, search for commas between
* the beginning delimiter, "{", and the end delimiter,
* "}", and change them to blank spaces.
*/
cptr2 = strchr(cptr, '{');
if (cptr2 != nullptr) {
ilen = strlen(cptr2);
for (i = 0; i < ilen; 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 to see if the side id error checks need to be skipped */
if (strstr(cptr, "checks_off")) {
if (problem->skip_checks < 0) {
problem->skip_checks = 1;
}
}
/* Check to see if using face definition of adjacency */
else if (strstr(cptr, "face_adj")) {
if (problem->face_adj < 0) {
problem->face_adj = 1;
}
}
/* Check if element columns are to be detected and fixed so
* that all elements of a column are in the same partition */
else if (strstr(cptr, "fix_columns")) {
problem->fix_columns = 1;
}
/* Check to see if looking for global mechanisms */
else if (strstr(cptr, "global_mech")) {
if (problem->global_mech < 0) {
problem->global_mech = 1;
}
}
/* Check to see if looking for introduced mechanisms */
else if (strstr(cptr, "local_mech")) {
if (problem->local_mech < 0) {
problem->local_mech = 1;
}
}
/* Check to see if looking for connected domains */
else if (strstr(cptr, "find_cnt_domains")) {
if (problem->find_cnt_domains < 0) {
problem->find_cnt_domains = 1;
}
}
/* Check to see if user wants to add processors to take care of
* introduced mechanisms
*/
else if (strstr(cptr, "mech_add_procs")) {
if (problem->mech_add_procs < 0) {
problem->mech_add_procs = 1;
}
}
/* Check to see if user wants to add processors to take care of
* introduced mechanisms
*/
else if (strstr(cptr, "dsd_add_procs")) {
if (problem->dsd_add_procs < 0) {
problem->dsd_add_procs = 1;
}
}
/* Check for treating spheres as concentrated masses*/
else if (strstr(cptr, "no_sph")) {
if (problem->no_sph < 0) {
problem->no_sph = 1;
}
}
/* Check for group designation sub-option */
else if (strstr(cptr, "groups")) {
/* "{" defines the beginning of the group designator */
cptr2 = strchr(cptr, '{');
if (cptr2 == nullptr) {
Gen_Error(0, "FATAL: group start designator \"}\" not found");
return 0;
}
cptr2++;
/* allocate space to hold the group designator */
problem->groups = reinterpret_cast<char *>(malloc(strlen(cptr2) + 1));
copy_string(problem->groups, cptr2, strlen(cptr2) + 1);
/* get rid of ending bracket */
cptr2 = strchr(problem->groups, '}');
*cptr2 = '\0';
}
else {
ctemp = fmt::format("WARNING: unknown miscellaneous suboption {}", cptr);
Gen_Error(1, ctemp);
}
cptr = strtok(nullptr, ",");
}
}
else {
/* Generate an error, but continue reading for an unknown key */
strip_string(inp_copy, " #\t");
if (strlen(inp_copy) > 5) {
ctemp = fmt::format(
"WARNING: don't know how to process line: \n{}\nin command file, ignored", inp_copy);
Gen_Error(1, ctemp);
}
}
} /* End "if(inp_line[0] != '#')" */
} /* End "while(fgets(inp_line, MAX_INP_LINE, inp_fd))" */
return 1;
} /*------------End read_cmd_file()---------------*/
/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
/* This function performs error checks on the user input.
*---------------------------------------------------------------------------*/
template int check_inp_specs(std::string &exoII_inp_file, std::string &nemI_out_file,
Machine_Description *machine, LB_Description<int> *lb,
Problem_Description *prob, Solver_Description *solver,
Weight_Description<int> *weight);
template int check_inp_specs(std::string &exoII_inp_file, std::string &nemI_out_file,
Machine_Description *machine, LB_Description<int64_t> *lb,
Problem_Description *prob, Solver_Description *solver,
Weight_Description<int64_t> *weight);
template <typename INT>
int check_inp_specs(std::string &exoII_inp_file, std::string &nemI_out_file,
Machine_Description *machine, LB_Description<INT> *lb,
Problem_Description *prob, Solver_Description *solver,
Weight_Description<INT> *weight)
{
/* Check that an input ExodusII file name was specified */
if (exoII_inp_file.empty()) {
Gen_Error(0, "FATAL: no input ExodusII file specified");
return 0;
}
/* Check for the existence and readability of the input file */
int icpu_ws = 0;
int iio_ws = 0;
float vers;
int exid_inp;
if ((exid_inp = ex_open(exoII_inp_file.c_str(), EX_READ, &icpu_ws, &iio_ws, &vers)) < 0) {
std::string ctemp = fmt::format("FATAL: unable to open input ExodusII file {}", exoII_inp_file);
Gen_Error(0, ctemp);
return 0;
}
/* Get the integer size stored on the database */
prob->int64db = ex_int64_status(exid_inp) & EX_ALL_INT64_DB;
ex_close(exid_inp);
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Check the machine specification */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (machine->type != MESH && machine->type != HCUBE) {
Gen_Error(0, "FATAL: machine type not properly set");
return 0;
}
if (machine->type == HCUBE && machine->num_dims != 1) {
Gen_Error(0, "FATAL: improper number of dimension for a hypercube, only"
" 1 allowed");
return 0;
}
if (machine->type == MESH && machine->num_dims > 3) {
Gen_Error(0, "FATAL: maximum of 3 dimensions for a mesh exceeded");
return 0;
}
/* non-cluster machines have only one box */
if (machine->num_boxes < 0) {
machine->num_boxes = 1;
}
/* Find out the number of processors */
if (machine->type == HCUBE) {
machine->procs_per_box = 1 << machine->dim[0];
}
else {
machine->procs_per_box = machine->dim[0];
for (int cnt = 1; cnt < machine->num_dims; cnt++) {
machine->procs_per_box *= machine->dim[cnt];
}
}
/* now calculate the total number of processors */
machine->num_procs = machine->num_boxes * machine->procs_per_box;
/*
* currently, do not allow groups and clusters since the
* loops to chaco get a bit too confusing
*/
if (machine->num_boxes > 1 && prob->groups != nullptr) {
Gen_Error(0, "FATAL: groups cannot be designated for a cluster machine");
return 0;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Check the problem specifications */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (prob->type != ELEMENTAL && prob->type != NODAL) {
Gen_Error(0, "FATAL: unknown problem type specified");
return 0;
}
if (prob->skip_checks < 0) {
prob->skip_checks = 0;
}
if (prob->face_adj < 0) {
prob->face_adj = 0;
}
/*
* using face definition of adjacencies only makes sense
* with an elemental decomposition
*/
if (prob->type != ELEMENTAL && prob->face_adj) {
Gen_Error(1, "WARNING: can only use face definition of");
Gen_Error(1, "WARNING: adjacency with elemental decomposition");
Gen_Error(1, "WARNING: face definition turned off");
prob->face_adj = 0;
}
/*
* Detecting columns and fixing their partitioning only makes sense
* with an elemental decomposition
*/
if (prob->type != ELEMENTAL && prob->fix_columns) {
Gen_Error(1, "WARNING: can only use fix columns options");
Gen_Error(1, "WARNING: with elemental decomposition");
Gen_Error(1, "WARNING: fix columns option turned off");
prob->fix_columns = 0;
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Check the load balance parameters */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (lb->type != MULTIKL && lb->type != SPECTRAL && lb->type != INERTIAL && lb->type != LINEAR &&
lb->type != RANDOM && lb->type != SCATTERED && lb->type != INFILE && lb->type != ZPINCH &&
lb->type != BRICK && lb->type != ZOLTAN_RCB && lb->type != ZOLTAN_RIB &&
lb->type != ZOLTAN_HSFC) {
Gen_Error(0, "FATAL: unknown load balance type requested");
return 0;
}
if ((sizeof(INT) == 8) && (lb->type != LINEAR && lb->type != SCATTERED)) {
Gen_Error(1, "WARNING: This mesh is using 64-bit integers. The only supported");
Gen_Error(1, " load balance methods for 64-bit integers are 'linear' or 'scattered'");
Gen_Error(1, " The load balance method will be automatically changed to 'linear'.");
lb->type = LINEAR;
}
if (lb->type == MULTIKL) {
lb->refine = KL_REFINE;
}
if (lb->refine != KL_REFINE && lb->refine != NO_REFINE) {
lb->refine = NO_REFINE; /* Default if not specified */
}
if (lb->num_sects <= 0) {
lb->num_sects = 1; /* Default if not specified */
}
if (lb->cnctd_dom < 0) {
lb->cnctd_dom = 0;
}
else if (!prob->face_adj) {
Gen_Error(1, "WARNING: can only set connected domain");
Gen_Error(1, "WARNING: when using face definition of adjacency");
Gen_Error(1, "WARNING: connected domain turned off");
lb->cnctd_dom = 0;
}
if (lb->outfile < 0) {
lb->outfile = ELB_FALSE;
}
if (lb->type == INFILE) {
if (lb->outfile) {
Gen_Error(0, "FATAL: both infile and outfile cannot be specified");
return 0;
}
if (lb->refine != NO_REFINE) {
Gen_Error(1, "WARNING: no refinement can be specified with infile");
return 0;
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Check the eigensolver parameters */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (lb->type == SPECTRAL || lb->type == MULTIKL) {
if (solver->tolerance < 0.0) {
Gen_Error(1, "WARNING: using default value for eigensolver"
" tolerance");
solver->tolerance = 1.0e-3;
}
if (solver->rqi_flag < 0) {
solver->rqi_flag = 0;
}
if (solver->vmax < 0) {
Gen_Error(1, "WARNING: no value for vmax specified,"
" using default");
solver->vmax = 200;
}
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Check the output file name */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (nemI_out_file.empty()) {
/*
* Generate the file name from the input file name and the requested
* load balance method.
*/
std::string ctemp2;
switch (machine->type) {
case MESH: ctemp2 = fmt::format("-m{}-", machine->num_procs); break;
case HCUBE: ctemp2 = fmt::format("-h{}-", machine->num_procs); break;
}
switch (lb->type) {
case MULTIKL:
case SPECTRAL:
if (lb->num_sects == 1) {
ctemp2 += "b";
}
else if (lb->num_sects == 2) {
ctemp2 += "q";
}
else if (lb->num_sects == 3) {
ctemp2 += "o";
}
break;
case INERTIAL: ctemp2 += "i"; break;
case ZPINCH: ctemp2 += "z"; break;
case BRICK: ctemp2 += "x"; break;
case ZOLTAN_RCB:
case ZOLTAN_RIB:
case ZOLTAN_HSFC: ctemp2 += "Z"; break;
case SCATTERED: ctemp2 += "s"; break;
case RANDOM: ctemp2 += "r"; break;
case LINEAR: ctemp2 += "l"; break;
}
if (lb->refine == KL_REFINE) {
ctemp2 += "KL";
}
/* Generate the complete file name */
nemI_out_file = remove_extension(exoII_inp_file);
nemI_out_file += ctemp2;
nemI_out_file += ".nemI";
} /* End "if(strlen(nemI_out_file) <= 0)" */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* Check the weighting specifications */
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if (weight->exo_filename.length() > 0) {
/* Check that a variable name and/or index was specified. */
if (weight->exo_varname.empty() && weight->exo_vindx <= 0) {
Gen_Error(0, "FATAL: must specify an index and/or a name for weighting"
" variable");
return 0;
}
/*
* If a variable name and or index was specified then open the ExodusII
* file and compare the specified name against what exists in the file.
*/
int exoid;
float version;
int cpu_ws = 0;
int io_ws = 0;
if ((exoid = ex_open(weight->exo_filename.c_str(), EX_READ, &cpu_ws, &io_ws, &version)) < 0) {
std::string ctemp =
fmt::format("FATAL: failed to open ExodusII weighting file {}", weight->exo_filename);
Gen_Error(0, ctemp);
return 0;
}
int ntimes = ex_inquire_int(exoid, EX_INQ_TIME);
/* Check the time index */
if (weight->exo_tindx <= 0) {
weight->exo_tindx = 1; /* Defaults to 1 */
}
if (weight->exo_tindx > ntimes) {
std::string ctemp = fmt::format(
"FATAL: requested time index %d not available in weighting file", weight->exo_tindx);
Gen_Error(0, ctemp);
return 0;
}
ex_entity_type type;
if (prob->type == NODAL) {
type = EX_NODAL;
}
else {
type = EX_ELEM_BLOCK;
}
/*
* First check that there are variables of the requested type in the
* specified ExodusII file.
*/
int nvars;
if (ex_get_variable_param(exoid, type, &nvars) < 0) {
Gen_Error(0, "FATAL: unable to get variable params from ExodusII"
" weighting file");
return 0;
}
if (nvars <= 0) {
Gen_Error(0, "FATAL: no variables found in the ExodusII weighting file");
return 0;
}
/* Read the variable names from the requested file */
char **var_names = reinterpret_cast<char **>(malloc(nvars * sizeof(char *)));
if (!var_names) {
Gen_Error(0, "FATAL: insufficient memory");
return 0;
}
{
int max_name_length = ex_inquire_int(exoid, EX_INQ_DB_MAX_USED_NAME_LENGTH);
ex_set_max_name_length(exoid, max_name_length);
for (int cnt = 0; cnt < nvars; cnt++) {
var_names[cnt] = reinterpret_cast<char *>(malloc((max_name_length + 1) * sizeof(char)));
if (!var_names[cnt]) {
Gen_Error(0, "FATAL: insufficient memory");
return 0;
}
}
}
if (ex_get_variable_names(exoid, type, nvars, var_names) < 0) {
Gen_Error(0, "FATAL: unable to obtain variable names for weighting");
return 0;
}
/*
* If there was a variable name specified but no index then get the
* index. If a variable name AND an index were specified then make
* sure they match.
*/
if (!weight->exo_varname.empty()) {
int tmp_vindx = 0;
for (int cnt = 0; cnt < nvars; cnt++) {
if (strcmp(var_names[cnt], weight->exo_varname.c_str()) == 0) {
tmp_vindx = cnt + 1;
break; /* out of "for" loop */
}
}
if (weight->exo_vindx <= 0) {
weight->exo_vindx = tmp_vindx;
}
else if (weight->exo_vindx != tmp_vindx) {
Gen_Error(0, "FATAL: requested weight variable index doesn't match"
" the variable name in the ExodusII file");
return 0;
}
}
/* Free up memory */
for (int cnt = 0; cnt < nvars; cnt++) {
free(var_names[cnt]);
}
free(var_names);
/*
* If there is still no valid index then the variable name does
* not exist in the specified file.
*/
if (weight->exo_vindx <= 0) {
std::string ctemp = fmt::format(
"FATAL: requested weighting variable {} not found in ExodusII file", weight->exo_varname);
Gen_Error(0, ctemp);
return 0;
}
if (nvars < weight->exo_vindx) {
Gen_Error(0, "FATAL: requested variable index is larger than number in"
" ExodusII weighting file");
return 0;
}
ex_close(exoid);
} /* End "if(strlen(weight->exo_filename) > 0)" */
if ((weight->type & EL_BLK) && (weight->ow_read)) {
if (weight->elemblk.size() > 1) {
/* start by sorting the two arrays by the element block number */
sort2(weight->elemblk.size(), weight->elemblk.data(), weight->elemblk_wgt.data());
/* now loop through, and make sure that we don't have multiple values */
for (int cnt = 1; cnt < (int)weight->elemblk.size(); cnt++) {
if (weight->elemblk[cnt] == weight->elemblk[cnt - 1]) {
std::string ctemp =
fmt::format("WARNING: multiple weight specified for block {}", weight->elemblk[cnt]);
Gen_Error(1, ctemp);
}
}
}
} /* if ((weight->type & EL_BLK) && (weight->ow_read)) */
return 1;
} /*-------------------End check_inp_specs()-----------------*/
namespace {
/* Parse comma separate list into words.
Copyright (C) 1996, 1997, 1999, 2004 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
const char *my_strchrnul(const char *s, int c)
{
const char *result = strchr(s, c);
if (!result) {
result = (char *)s + strlen(s);
}
return (result);
}
/* Parse comma separated suboption from *OPTIONP and match against
strings in TOKENS. If found return index and set *VALUEP to
optional value introduced by an equal sign. If the suboption is
not part of TOKENS return in *VALUEP beginning of unknown
suboption. On exit *OPTIONP is set to the beginning of the next
token or at the terminating NUL character. */
int my_getsubopt(char **optionp, char *const *tokens, char **valuep)
{
if (**optionp == '\0')
return -1;
/* Find end of next token. */
char *endp = (char *)my_strchrnul(*optionp, ',');
/* Find start of value. */
char *vstart = (char *)memchr(*optionp, '=', endp - *optionp);
if (vstart == nullptr)
vstart = endp;
/* Try to match the characters between *OPTIONP and VSTART against
one of the TOKENS. */
for (int cnt = 0; tokens[cnt] != nullptr; ++cnt)
if (strncmp(*optionp, tokens[cnt], vstart - *optionp) == 0 &&
tokens[cnt][vstart - *optionp] == '\0') {
/* We found the current option in TOKENS. */
*valuep = vstart != endp ? vstart + 1 : nullptr;
if (*endp != '\0')
*endp++ = '\0';
*optionp = endp;
return cnt;
}
/* The current suboption does not match any option. */
*valuep = *optionp;
if (*endp != '\0')
*endp++ = '\0';
*optionp = endp;
return -1;
}
void print_usage()
{
fmt::print("\nusage:\t{} [-h] [<-n|-e> -o <output file>"
" -m <machine description>\n"
"\t -l <load bal description> -s <eigen solver specs>\n"
"\t -w <weighting options> -g <group list> -f]\n"
"\t [-a <ascii file>] exoII_file\n\n"
" -32\t\tforce use of 32-bit integers\n"
" -64\t\tforce use of 64-bit integers\n"
" -n\t\tperform a nodal based load balance\n"
" -e\t\tperform an elemental based load balance\n"
" -o NemI file\toutput NemesisI load-balance file name\n"
" -m mach desc\tdescription of the machine to load balance for\n"
" -l LB data\tload balance specifications\n"
" -s Eigen specs\tEigen solver specifications\n"
" -w weighting\tweighting specs for load balance\n"
" -g groupings\tgrouping specifications for load balance\n"
" -f\t\tuse face definition of adjacency\n"
" -p\t\tuse partial definition of adjacency: \n"
" \t\trequire only 3 matching quad face nodes\n"
" -C\tavoid splitting vertical element columns\n"
" \t\tacross partitions\n"
" -h\t\tusage information\n"
" -a ascii file\tget info from ascii input file name\n",
UTIL_NAME);
}
} // namespace