/* * 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 // for nullptr, stderr, etc #include // for exit, realloc #include // for strtok, strchr, strstr, etc #include #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 int read_pexoII_info(NemSpread &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( 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 &spreader, const char *filename); template int read_pexoII_info(NemSpread &spreader, const char *filename); template int read_pexoII_info(NemSpread &spreader, const char *filename); template int read_pexoII_info(NemSpread &spreader, const char *filename);