From 39bca682ea8c1e08ddfbf783fa24f5a41aa54daf Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 29 Dec 2023 15:46:10 -0700 Subject: [PATCH 01/27] Create new SW_netCDF.c function stubs for the branch - New/modified function subs * Correct the arguments of `SW_NC_create_template()` * `SW_NC_create_progress()` - Create a new progress netCDF file * `SW_NC_set_progress()` - Mark a certain site/grid cell as completed * `SW_NC_check_progress()` - See if the specific site/grid cell is marked to run --- include/SW_netCDF.h | 13 +++++++-- src/SW_netCDF.c | 67 +++++++++++++++++++++++++++++++++++++-------- 2 files changed, 66 insertions(+), 14 deletions(-) diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index 0078fd338..8d3dd33b8 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -21,9 +21,16 @@ extern "C" { void SW_NC_check(SW_DOMAIN* SW_Domain, int ncFileID, const char* fileName, LOG_INFO* LogInfo); void SW_NC_create_domain_template(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); -void SW_NC_create_template(const char* fileName, unsigned long timeSize, - unsigned long vertSize, const char* varName, - char* varAttributes[], LOG_INFO* LogInfo); +void SW_NC_create_template(const char* domFile, int domFileID, + const char* fileName, int* newFileID, int newVarType, + unsigned long timeSize, unsigned long vertSize, const char* varName, + const char* attNames[], const char* attVals[], int numAtts, LOG_INFO* LogInfo); +void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); +void SW_NC_set_progress(const char* domType, int progFileID, + const char* progVarName, unsigned long ncSUID[], + LOG_INFO* LogInfo); +Bool SW_NC_check_progress(int progFileID, const char* progVarName, + unsigned long ncSUID[], LOG_INFO* LogInfo); void SW_NC_read_inputs(SW_ALL* sw, SW_DOMAIN* SW_Domain, unsigned long ncSUID[], LOG_INFO* LogInfo); void SW_NC_check_input_files(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 8fa18ccaf..d876a3cf5 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1652,24 +1652,69 @@ void SW_NC_create_domain_template(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { } /** - * @brief Copy domain netCDF to a new file and make it ready for a new variable + * @brief Copy domain netCDF to a new file and add a new variable * + * @param[in] domFile Name of the domain netCDF + * @param[in] domFileID Identifier of the domain netCDF file * @param[in] fileName Name of the netCDF file to create + * @param[in] newFileID Identifier of the netCDF file to create + * @param[in] newVarType Type of the variable to create * @param[in] timeSize Size of "time" dimension * @param[in] vertSize Size of "vertical" dimension * @param[in] varName Name of variable to write - * @param[in] varAttributes Attributes that the new variable will contain + * @param[in] attNames Attribute names that the new variable will contain + * @param[in] attVals Attribute values that the new variable will contain + * @param[in] numAtts Number of attributes being sent in * @param[in,out] LogInfo Holds information dealing with logfile output */ -void SW_NC_create_template(const char* fileName, unsigned long timeSize, - unsigned long vertSize, const char* varName, - char* varAttributes[], LOG_INFO* LogInfo) { - (void) fileName; - (void) timeSize; - (void) vertSize; - (void) varName; - (void) varAttributes; - (void) LogInfo; +void SW_NC_create_template(const char* domFile, int domFileID, + const char* fileName, int* newFileID, int newVarType, + unsigned long timeSize, unsigned long vertSize, const char* varName, + const char* attNames[], const char* attVals[], int numAtts, LOG_INFO* LogInfo) { + +} + +/** + * @brief Create a progress netCDF file + * + * @param[in,out] SW_Domain Struct of type SW_DOMAIN holding constant + * temporal/spatial information for a set of simulation runs + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { + +} + +/** + * @brief Mark a site/gridcell as completed in the progress file + * + * @param[in] domType Type of domain in which simulations are running + * (gridcell/sites) + * @param[in] progFileID Identifier of the progress netCDF file + * @param[in] progVarName User-specified progress variable name + * @param[in] ncSUID Current simulation unit identifier for which is used + * to get data from netCDF + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +void SW_NC_set_progress(const char* domType, int progFileID, + const char* progVarName, unsigned long ncSUID[], + LOG_INFO* LogInfo) { + +} + +/** + * @brief Check if a site/grid cell is marked to be run in the progress + * netCDF + * + * @param[in] progFileID Identifier of the progress netCDF file + * @param[in] progVarName User-specified progress variable name + * @param[in] ncSUID Current simulation unit identifier for which is used + * to get data from netCDF + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +Bool SW_NC_check_progress(int progFileID, const char* progVarName, + unsigned long ncSUID[], LOG_INFO* LogInfo) { + } /** From 4de69cde093dee591190efaab8fa66b20aff1c20 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 29 Dec 2023 15:46:18 -0700 Subject: [PATCH 02/27] New input file - `progress.nc` - Now allow a new input netCDF file - progress.nc - Add example for "progress.nc" in files_nc.in - Update `SW_NC_open_files()` to open the progress netCDF with writing ability --- include/SW_datastructs.h | 2 +- include/SW_netCDF.h | 1 + src/SW_netCDF.c | 13 +++++++++---- tests/example/Input_nc/files_nc.in | 3 ++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/SW_datastructs.h b/include/SW_datastructs.h index ffd9b6842..47f1c59e6 100644 --- a/include/SW_datastructs.h +++ b/include/SW_datastructs.h @@ -26,7 +26,7 @@ #endif #define SW_NFILES 26 // For `InFiles` -#define SW_NVARNC 1 // For `InFilesNC` +#define SW_NVARNC 2 // For `InFilesNC` /* =================================================== */ diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index 8d3dd33b8..8401253fe 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -12,6 +12,7 @@ extern "C" { /* --------------------------------------------------- */ #define DOMAIN_NC 0 // Domain netCDF index within `InFilesNC` and `varNC` (SW_NETCDF) +#define PROG_NC 1 // Progress netCDF index within `InFilesNC` and `varNC` (SW_NETCDF) #define DOMAIN_TEMP "Input_nc/domain_template.nc" diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index d876a3cf5..120650498 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -14,7 +14,7 @@ /* Local Defines */ /* --------------------------------------------------- */ -#define NUM_NC_IN_KEYS 1 // Number of possible keys within `files_nc.in` +#define NUM_NC_IN_KEYS 2 // Number of possible keys within `files_nc.in` #define NUM_ATT_IN_KEYS 25 // Number of possible keys within `attributes_nc.in` /* =================================================== */ @@ -1795,7 +1795,7 @@ void SW_NC_check_input_files(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * @param[in,out] LogInfo Holds information dealing with logfile output */ void SW_NC_read(SW_NETCDF* SW_netCDF, PATH_INFO* PathInfo, LOG_INFO* LogInfo) { - static const char* possibleKeys[] = {"domain"}; + static const char* possibleKeys[] = {"domain", "progress"}; FILE *f; char inbuf[MAX_FILENAMESIZE], *MyFileName; @@ -1816,6 +1816,9 @@ void SW_NC_read(SW_NETCDF* SW_netCDF, PATH_INFO* PathInfo, LOG_INFO* LogInfo) { SW_netCDF->varNC[DOMAIN_NC] = Str_Dup(varName, LogInfo); SW_netCDF->InFilesNC[DOMAIN_NC] = Str_Dup(path, LogInfo); break; + case PROG_NC: + SW_netCDF->varNC[PROG_NC] = Str_Dup(varName, LogInfo); + SW_netCDF->InFilesNC[PROG_NC] = Str_Dup(path, LogInfo); default: LogError(LogInfo, LOGWARN, "Ignoring unknown key in %s, %s", MyFileName, key); @@ -1902,11 +1905,13 @@ void SW_NC_deconstruct(SW_NETCDF* SW_netCDF) { * netCDF file information */ void SW_NC_open_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo) { - int fileNum; + int fileNum, openType; for(fileNum = 0; fileNum < SW_NVARNC; fileNum++) { if(FileExists(SW_netCDF->InFilesNC[fileNum])) { - if(nc_open(SW_netCDF->InFilesNC[fileNum], NC_NOWRITE, + openType = (fileNum == PROG_NC) ? NC_WRITE : NC_NOWRITE; + + if(nc_open(SW_netCDF->InFilesNC[fileNum], openType, &SW_netCDF->ncFileIDs[fileNum]) != NC_NOERR) { LogError(LogInfo, LOGERROR, "An error occurred when opening %s.", diff --git a/tests/example/Input_nc/files_nc.in b/tests/example/Input_nc/files_nc.in index 91157be10..46911be56 100644 --- a/tests/example/Input_nc/files_nc.in +++ b/tests/example/Input_nc/files_nc.in @@ -5,4 +5,5 @@ # The second value is the path of the netCDF file. # This convention eliminates the possibility of incorrect reads due to line dependencies. -domain domain Input_nc/domain.nc \ No newline at end of file +domain domain Input_nc/domain.nc +progress progress Input_nc/progress.nc \ No newline at end of file From 575008b16c8d4b86d7034be5f1767cf852d0480a Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 5 Jan 2024 11:37:42 -0700 Subject: [PATCH 03/27] Correct function headers in `SW_Domain.c`/`SW_netCDF.c` - `SW_NC_create_template()` gains arguments for frequency and input attribute for new netCDFs - `SW_NC_set_progress()`/`SW_DOM_SetProgress()` swaps progress variable name for variable ID - `SW_NC_check_progress()`/`SW_DOM_CheckProgress()` swaps progress variable name for variable ID --- include/SW_Domain.h | 9 ++++++--- include/SW_netCDF.h | 7 ++++--- src/SW_Domain.c | 24 ++++++++++++++++-------- src/SW_netCDF.c | 13 ++++++++----- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/include/SW_Domain.h b/include/SW_Domain.h index 7a951a2b8..042c1799c 100644 --- a/include/SW_Domain.h +++ b/include/SW_Domain.h @@ -13,10 +13,13 @@ extern "C" { void SW_DOM_calc_ncSuid(SW_DOMAIN* SW_Domain, unsigned long suid, unsigned long ncSuid[]); void SW_DOM_calc_nSUIDs(SW_DOMAIN* SW_Domain); -Bool SW_DOM_CheckProgress(char* domainType, unsigned long ncSuid[]); -void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain); +Bool SW_DOM_CheckProgress(int progFileID, int progVarID, + unsigned long ncSuid[], LOG_INFO* LogInfo); +void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); -void SW_DOM_SetProgress(char* domainType, unsigned long ncSuid[]); +void SW_DOM_SetProgress(const char* domType, int progFileID, + int progVarID, unsigned long ncSuid[], + LOG_INFO* LogInfo); void SW_DOM_SimSet(SW_DOMAIN* SW_Domain, unsigned long userSUID, LOG_INFO* LogInfo); void SW_DOM_deepCopy(SW_DOMAIN* source, SW_DOMAIN* dest, LOG_INFO* LogInfo); diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index 244776553..a4b6d73bd 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -25,12 +25,13 @@ void SW_NC_create_domain_template(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); void SW_NC_create_template(const char* domFile, int domFileID, const char* fileName, int* newFileID, int newVarType, unsigned long timeSize, unsigned long vertSize, const char* varName, - const char* attNames[], const char* attVals[], int numAtts, LOG_INFO* LogInfo); + const char* attNames[], const char* attVals[], int numAtts, Bool isInput, + const char* freq, LOG_INFO* LogInfo); void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); void SW_NC_set_progress(const char* domType, int progFileID, - const char* progVarName, unsigned long ncSUID[], + int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo); -Bool SW_NC_check_progress(int progFileID, const char* progVarName, +Bool SW_NC_check_progress(int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo); void SW_NC_read_inputs(SW_ALL* sw, SW_DOMAIN* SW_Domain, unsigned long ncSUID[], LOG_INFO* LogInfo); diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 71dafab1f..41c06931b 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -63,17 +63,18 @@ void SW_DOM_calc_nSUIDs(SW_DOMAIN* SW_Domain) { /** * @brief Check progress in domain * - * @param[in] domainType Type of domain in which simulations are running - * (gridcell/sites) - * @param[in] ncSuid Current simulation unit identifier for which progress - * should be checked. + * @param[in] progFileID Identifier of the progress netCDF file + * @param[in] progVarID Identifier of the progress variable + * @param[in] ncSuid Current simulation unit identifier for which is used + * to get data from netCDF + * @param[in,out] LogInfo Holds information dealing with logfile output * * @return * TRUE if simulation for \p ncSuid has not been completed yet; * FALSE if simulation for \p ncSuid has been completed (i.e., skip). */ -Bool SW_DOM_CheckProgress(char* domainType, unsigned long ncSuid[]) { - (void) domainType; +Bool SW_DOM_CheckProgress(int progFileID, int progVarID, + unsigned long ncSuid[], LOG_INFO* LogInfo) { (void) ncSuid; // return TRUE (due to lack of capability to track progress) @@ -85,8 +86,9 @@ Bool SW_DOM_CheckProgress(char* domainType, unsigned long ncSuid[]) { * * @param[in] SW_Domain Struct of type SW_DOMAIN holding constant * temporal/spatial information for a set of simulation runs + * @param[in] LogInfo Holds information dealing with logfile output */ -void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain) { +void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { (void) SW_Domain; } @@ -243,13 +245,19 @@ void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { /** * @brief Mark a completed suid in progress netCDF * - * @param[in] domainType Type of domain in which simulations are running + * @param[in] domType Type of domain in which simulations are running * (gridcell/sites) + * @param[in] progFileID Identifier of the progress netCDF file + * @param[in] progVarID Identifier of the progress variable * @param[in] ncSuid Unique indentifier of the first suid to run * in relation to netCDFs + * @param[in,out] LogInfo */ void SW_DOM_SetProgress(char* domainType, unsigned long ncSuid[]) { (void) domainType; +void SW_DOM_SetProgress(const char* domType, int progFileID, + int progVarID, unsigned long ncSuid[], + LOG_INFO* LogInfo) { (void) ncSuid; } diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index b549c26b0..29924f0ac 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1680,12 +1680,15 @@ void SW_NC_create_domain_template(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * @param[in] attNames Attribute names that the new variable will contain * @param[in] attVals Attribute values that the new variable will contain * @param[in] numAtts Number of attributes being sent in + * @param[in] isInput Specifies if the created file will be input or output + * @param[in] freq Value of the global attribute "frequency" * @param[in,out] LogInfo Holds information dealing with logfile output */ void SW_NC_create_template(const char* domFile, int domFileID, const char* fileName, int* newFileID, int newVarType, unsigned long timeSize, unsigned long vertSize, const char* varName, - const char* attNames[], const char* attVals[], int numAtts, LOG_INFO* LogInfo) { + const char* attNames[], const char* attVals[], int numAtts, Bool isInput, + const char* freq, LOG_INFO* LogInfo) { } @@ -1706,13 +1709,13 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * @param[in] domType Type of domain in which simulations are running * (gridcell/sites) * @param[in] progFileID Identifier of the progress netCDF file - * @param[in] progVarName User-specified progress variable name + * @param[in] progVarID Identifier of the progress variable within the progress netCDF * @param[in] ncSUID Current simulation unit identifier for which is used * to get data from netCDF * @param[in,out] LogInfo Holds information dealing with logfile output */ void SW_NC_set_progress(const char* domType, int progFileID, - const char* progVarName, unsigned long ncSUID[], + int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { } @@ -1722,12 +1725,12 @@ void SW_NC_set_progress(const char* domType, int progFileID, * netCDF * * @param[in] progFileID Identifier of the progress netCDF file - * @param[in] progVarName User-specified progress variable name + * @param[in] progVarID Identifier of the progress variable * @param[in] ncSUID Current simulation unit identifier for which is used * to get data from netCDF * @param[in,out] LogInfo Holds information dealing with logfile output */ -Bool SW_NC_check_progress(int progFileID, const char* progVarName, +Bool SW_NC_check_progress(int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { } From d021c0b3b95513e8a97a323cb39f11b237812f95 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 5 Jan 2024 11:55:19 -0700 Subject: [PATCH 04/27] SW_NETCDF stores variable IDs + update `SW_NC_open_files()` - This new variable will store the main variable IDs within a given netCDF so retrieving that information does not happen many times a run - Simplified `SW_NC_open_files()` and function now gets the variable ID within the netCDF which was opened --- include/SW_datastructs.h | 1 + src/SW_netCDF.c | 19 +++++++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/include/SW_datastructs.h b/include/SW_datastructs.h index cf2b4ea73..dec36a820 100644 --- a/include/SW_datastructs.h +++ b/include/SW_datastructs.h @@ -1066,6 +1066,7 @@ typedef struct { char *InFilesNC[SW_NVARNC]; int ncFileIDs[SW_NVARNC]; + int ncVarIDs[SW_NVARNC]; } SW_NETCDF; /* =================================================== */ diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 29924f0ac..437385e25 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1947,18 +1947,25 @@ void SW_NC_deconstruct(SW_NETCDF* SW_netCDF) { * netCDF file information */ void SW_NC_open_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo) { - int fileNum, openType; + int fileNum, openType, *fileID; + char* fileName; for(fileNum = 0; fileNum < SW_NVARNC; fileNum++) { - if(FileExists(SW_netCDF->InFilesNC[fileNum])) { - openType = (fileNum == vNCprog) ? NC_WRITE : NC_NOWRITE; + fileName = SW_netCDF->InFilesNC[fileNum]; + fileID = &SW_netCDF->ncFileIDs[fileNum]; - if(nc_open(SW_netCDF->InFilesNC[fileNum], openType, - &SW_netCDF->ncFileIDs[fileNum]) != NC_NOERR) { + if(FileExists(fileName)) { + openType = (fileNum == vNCprog) ? NC_WRITE : NC_NOWRITE; + if(nc_open(fileName, openType, fileID) != NC_NOERR) { LogError(LogInfo, LOGERROR, "An error occurred when opening %s.", - SW_netCDF->InFilesNC[fileNum]); + fileName); + return; // Exit function prematurely due to error + } + get_var_identifier(*fileID, SW_netCDF->varNC[fileNum], + &SW_netCDF->ncVarIDs[fileNum], LogInfo); + if(LogInfo->stopRun) { return; // Exit function prematurely due to error } } From bcf2d8b03ab320d27287939fcf404f365919459e Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 5 Jan 2024 14:19:28 -0700 Subject: [PATCH 05/27] Fill `SW_NC_create_template()` - Using the `domain.nc` file, the function will * Make a copy and fill the new template with a given variable, dimension(s) if needed and update the global attributes - New function `update_netCDF_global_atts()` which * Is used by `SW_NC_create_template()` * Updates the global attributes frequency, creation date, product, feature type, and source within the generated template --- src/SW_netCDF.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 437385e25..5fdde98b2 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1279,6 +1279,55 @@ static void fill_netCDF_with_global_atts(SW_NETCDF* SW_netCDF, int* ncFileID, } } +/** + * @brief Overwrite specific global attributes into a new file + * + * @param[in] ncFileID Identifier of the open netCDF file to write all information to + * @param[in] domType Type of domain in which simulations are running + * (gridcell/sites) + * @param[in] freqAtt Value of a global attribute "frequency" (may be "fx", + * "day", "week", "month", or "year") + * @param[in] isInputFile Specifies if the file being written to is input + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +static void update_netCDF_global_atts(int* ncFileID, const char* domType, + const char* freqAtt, Bool isInputFile, LOG_INFO* LogInfo) { + + char sourceStr[40]; // 40 - valid size of the SOILWAT2 global `SW2_VERSION` + "SOILWAT2" + char creationDateStr[21]; // 21 - valid size to hold a string of format YYYY-MM-DDTHH:MM:SSZ + time_t t = time(NULL); + + int attNum; + const int numGlobAtts = (strcmp(domType, "s") == 0) ? 5 : 4; // Do or do not include "featureType" + const char* attNames[] = { + "source", "creation_date", "product", "frequency", "featureType" + }; + + const char* productStr = (isInputFile) ? "model-input" : "model-output"; + const char* featureTypeStr; + if(strcmp(domType, "s") == 0) { + featureTypeStr = (dimExists("time", *ncFileID)) ? "timeSeries" : "point"; + } else { + featureTypeStr = ""; + } + + const char* attVals[] = { + sourceStr, creationDateStr, productStr, freqAtt, featureTypeStr + }; + + // Fill `sourceStr` and `creationDateStr` + snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); + strftime(creationDateStr, sizeof creationDateStr, "%FT%TZ", gmtime(&t)); + + // Write out the necessary global attributes that are listed above + for(attNum = 0; attNum < numGlobAtts; attNum++) { + write_str_att(attNames[attNum], attVals[attNum], NC_GLOBAL, *ncFileID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + } +} + /** * @brief Wrapper function to fill a netCDF with all the invariant information * i.e., global attributes (including time created) and CRS information @@ -1690,6 +1739,69 @@ void SW_NC_create_template(const char* domFile, int domFileID, const char* attNames[], const char* attVals[], int numAtts, Bool isInput, const char* freq, LOG_INFO* LogInfo) { + int dimArrSize = 0, index, varID = 0; + int dimIDs[4]; // Maximum expected number of dimensions + Bool siteDimExists = dimExists("site", domFileID); + const char* latName = (dimExists("lat", domFileID)) ? "lat" : "y"; + const char* lonName = (dimExists("lon", domFileID)) ? "lon" : "x"; + const char* domType = (siteDimExists) ? "s" : "xy"; + int numConstDims = (siteDimExists) ? 1 : 2; + const char* thirdDim = (siteDimExists) ? "site" : latName; + const char* constDimNames[] = {thirdDim, lonName}; + const char* timeVertNames[] = {"time", "vertical"}; + int timeVertVals[] = {timeSize, vertSize}, numTimeVertVals = 2; + + CopyFile(domFile, fileName, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + if(nc_open(fileName, NC_WRITE, newFileID) != NC_NOERR) { + LogError(LogInfo, LOGERROR, "An error occurred when attempting " + "to access the new file %s.", fileName); + return; // Exit function prematurely due to error + } + + for(index = 0; index < numTimeVertVals; index++) { + if(timeVertVals[index] > 0) { + create_netCDF_dim(timeVertNames[index], timeSize, newFileID, + &dimIDs[dimArrSize], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + dimArrSize++; + } + } + + for(index = 0; index < numConstDims; index++) { + get_dim_identifier(*newFileID, constDimNames[index], + &dimIDs[dimArrSize], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + dimArrSize++; + } + + create_netCDF_var(&varID, varName, dimIDs, newFileID, newVarType, + dimArrSize, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + update_netCDF_global_atts(newFileID, domType, freq, isInput, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + for(index = 0; index < numAtts; index++) { + write_str_att(attNames[index], attVals[index], + varID, *newFileID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + } } /** From 819a36822d441154586263aa7a3ab4832462ddbb Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 5 Jan 2024 14:20:13 -0700 Subject: [PATCH 06/27] Fill `SW_NC_CreateProgress()` - `SW_NC_CreateProgress()` now creates a special netCDF file - progress - that keeps track of the suids that will not be/are to be/have run - The progress variable is filled with values that match the domain variable values within `domain.nc` so * If a suid is to be run, the progress variable value will be 0 * If a suid has been run, the progress variable will be 1 * If a suid is not to be run, the progress variable will be byte _FillValue (-127) - New function `fill_prog_netCDF_vals()` which fills the progress variable with a value pattern matching `domain.nc` (run or do not run) - New function `write_byte_att()` which writes an attribute of type byte to a netCDF - New function `fill_netCDF_var_byte()` - writing all values to a netCDF variable - New function `get_single_uint_val()` - get a value of type unsigned integer (currently from a domain variable) - Updated `SW_DOM_CreateProgress()` to call it's netCDF counterpart --- src/SW_Control.c | 5 ++ src/SW_Domain.c | 5 ++ src/SW_netCDF.c | 154 ++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 163 insertions(+), 1 deletion(-) diff --git a/src/SW_Control.c b/src/SW_Control.c index dc470c500..6a89fe83b 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -376,6 +376,11 @@ void SW_CTL_setup_domain(unsigned long userSUID, } #endif + SW_DOM_CreateProgress(SW_Domain, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + SW_DOM_SimSet(SW_Domain, userSUID, LogInfo); } diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 41c06931b..961da9f17 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -89,7 +89,12 @@ Bool SW_DOM_CheckProgress(int progFileID, int progVarID, * @param[in] LogInfo Holds information dealing with logfile output */ void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { + #if defined(SWNETCDF) + SW_NC_create_progress(SW_Domain, LogInfo); + #else (void) SW_Domain; + (void) LogInfo; + #endif } /** diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 5fdde98b2..d12253c06 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -9,6 +9,8 @@ #include "include/SW_Defines.h" #include "include/SW_Files.h" #include "include/myMemory.h" +#include "include/Times.h" +#include "include/SW_Domain.h" /* =================================================== */ /* Local Defines */ @@ -375,6 +377,24 @@ static void get_single_double_val(int ncFileID, const char* varName, } } +/** + * @brief Get an unsigned integer value from a variable + * + * @param[in] ncFileID Identifier of the open netCDF file to access + * @param[in] varID Identifier of the variable + * @param[in] index Location of the value within the variable + * @param[out] value String buffer to hold the resulting value + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +static void get_single_uint_val(int ncFileID, int varID, size_t index[], + unsigned int* value, LOG_INFO* LogInfo) { + + if(nc_get_var1_uint(ncFileID, varID, index, value) != NC_NOERR) { + LogError(LogInfo, LOGERROR, "An error occurred when trying to " + "get a value from a variable of type " + "unsigned integer."); + } +} /** * @brief Get a dimension value from a given netCDF file * @@ -477,6 +497,27 @@ static void fill_netCDF_var_uint(int ncFileID, int varID, unsigned int values[], } } +/** + * @brief Fills a variable with value(s) of type byte + * + * @param[in] ncFileID Identifier of the open netCDF file to write the value(s) to + * @param[in] varID Identifier to the variable within the given netCDF file + * @param[in] values Individual or list of input variables + * @param[in] startIndices Specification of where the C-provided netCDF + * should start writing values within the specified variable + * @param[in] count How many values to write into the given variable + * @param[out] LogInfo Holds information dealing with logfile output +*/ +static void fill_netCDF_var_byte(int ncFileID, int varID, const signed char values[], + size_t startIndices[], size_t count[], + LOG_INFO* LogInfo) { + + if(nc_put_vara_schar(ncFileID, varID, startIndices, count, &values[0]) != NC_NOERR) { + LogError(LogInfo, LOGERROR, "Could not fill variable (byte) " + "with the given value(s)."); + } +} + /** * @brief Fills a variable with value(s) of type double * @@ -499,7 +540,25 @@ static void fill_netCDF_var_double(int ncFileID, int varID, double values[], } /** - * @brief Write an attribute of type unsigned integer to a variable + * @brief Write a local attribute of type byte + * + * @param[in] attName Name of the attribute to create + * @param[in] attVal Value to write out + * @param[in] varID Identifier of the variable to add the attribute to + * @param[in] ncFileID Identifier of the open netCDF file to write the attribute to + * @param[out] LogInfo Holds information dealing with logfile output +*/ +static void write_byte_att(const char* attName, const signed char attVal, + int varID, int ncFileID, LOG_INFO* LogInfo) { + + if(nc_put_att_schar(ncFileID, varID, attName, NC_BYTE, 1, &attVal) != NC_NOERR) { + LogError(LogInfo, LOGERROR, "Could not create new attribute %s", + attName); + } +} + +/** + * @brief Write a global attribute (text) to a netCDF file * * @param[in] attName Name of the attribute to create * @param[in] attVal Attribute string to write out @@ -556,6 +615,50 @@ static void write_double_att(const char* attName, const double* attVal, int varI } } +/** + * @brief Fill the progress variable in the progress netCDF with values + * + * @param[in] SW_Domain Struct of type SW_DOMAIN holding constant + * temporal/spatial information for a set of simulation runs + * @param[in,out] LogInfo Holds information on warnings and errors +*/ +static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { + + int domVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCdom]; + int progVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCprog]; + signed char readyVal = 0; + unsigned int domStatus; + unsigned long suid, ncSuid[2], nSUIDs = SW_Domain->nSUIDs; + unsigned long nDimY = SW_Domain->nDimY, nDimX = SW_Domain->nDimX; + int progFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCprog]; + int domFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCdom]; + signed char* vals = (signed char*)Mem_Malloc(nSUIDs * sizeof(signed char), + "fill_prog_netCDF_vals()", + LogInfo); + size_t* start = (strcmp(SW_Domain->DomainType, "s") == 0) ? + (size_t[1]){0} : (size_t[2]){0, 0}; + size_t* count = (strcmp(SW_Domain->DomainType, "s") == 0) ? + (size_t[1]){nSUIDs} : (size_t[2]){nDimY, nDimX}; + + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + for(suid = 0; suid < nSUIDs; suid++) { + SW_DOM_calc_ncSuid(SW_Domain, suid, ncSuid); + + get_single_uint_val(domFileID, domVarID, ncSuid, &domStatus, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + vals[suid] = (domStatus == NC_FILL_UINT) ? NC_FILL_BYTE : readyVal; + } + + fill_netCDF_var_byte(progFileID, progVarID, vals, start, count, LogInfo); + nc_sync(progFileID); +} + /** * @brief Create a dimension within a netCDF file * @@ -1813,6 +1916,55 @@ void SW_NC_create_template(const char* domFile, int domFileID, */ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { + SW_NETCDF* SW_netCDF = &SW_Domain->netCDFInfo; + Bool primCRSIsGeo = SW_Domain->netCDFInfo.primary_crs_is_geographic; + Bool domTypeIsS = strcmp(SW_Domain->DomainType, "s") == 0; + const char* projGridMap = "crs_projsc: x y crs_geogsc: lat lon"; + const char* geoGridMap = "crs_geogsc"; + const char* sCoord = "lat lon site"; + const char* xyCoord = "lat lon"; + const char* coord = domTypeIsS ? sCoord : xyCoord; + const char* grid_map = primCRSIsGeo ? geoGridMap : projGridMap; + const char* attNames[] = {"long_name", "units", "grid_mapping", + "coordinates"}; + const char* attVals[] = {"simulation progress", "1", grid_map, coord}; + const int numAtts = 4; + const signed char fillVal = NC_FILL_BYTE; + const char* varName = SW_netCDF->varNC[vNCprog]; + const char* freq = "fx"; + + int domFileID = SW_netCDF->ncFileIDs[vNCdom]; + int* progFileID = &SW_netCDF->ncFileIDs[vNCprog]; + const char* domFileName = SW_netCDF->InFilesNC[vNCdom]; + const char* progFileName = SW_netCDF->InFilesNC[vNCprog]; + int* progVarID = &SW_netCDF->ncVarIDs[vNCprog]; + + if(FileExists(SW_Domain->netCDFInfo.InFilesNC[vNCprog])) { + SW_NC_check(SW_Domain, *progFileID, progFileName, LogInfo); + } else { + SW_NC_create_template(domFileName, domFileID, progFileName, + progFileID, NC_BYTE, 0, 0, varName, + attNames, attVals, numAtts, swFALSE, freq, + LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + // Write out the attribute "_FillValue" to the progress variable + get_var_identifier(*progFileID, varName, progVarID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + write_byte_att("_FillValue", fillVal, *progVarID, *progFileID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + nc_enddef(*progFileID); + + fill_prog_netCDF_vals(SW_Domain, LogInfo); + } } /** From 0450407ffcf62631d4b1f97a92e07608e38dc0a5 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 5 Jan 2024 14:33:23 -0700 Subject: [PATCH 07/27] Fill `SW_NC_set_progress`/`SW_NC_check_progress()` - Filled both functions and are no longer a stub and with their SW_Domain.c counterparts SW_NC_check_progress()/SW_DOM_CheckProgress() - SW_NC_check_progress() * Checks a specific SUID within the progress variable to see if it should be run/simulated - SW_DOM_CheckProgress() * Calls the netCDF counterpart * Update calls to the function, mainly due to the addition of LOG_INFO * Silences compiler when SW_NETCDF is not defined SW_NC_set_progress()/SW_DOM_SetProgress - SW_NC_set_progress() * When a SUID is done simulating, this function will mark the location within the progress variable as completed - SW_DOM_SetProgress() * Now calls its netCDF counter part * Silences compiler when SW_NETCDF is not defined - New function `get_single_byte_val()` which obtains the status at the current SUID to test - Modified the code within `SW_DOM_SimSet()` and `SW_CTL_RunSimSet()` in response to the addition of LOG_INFO in `SW_DOM_CheckProgress()` --- src/SW_Control.c | 37 +++++++++++++++++++++++-------------- src/SW_Domain.c | 33 +++++++++++++++++++++++++++++---- src/SW_netCDF.c | 30 ++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/src/SW_Control.c b/src/SW_Control.c index 6a89fe83b..a46f2b044 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -210,7 +210,14 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], char tag_suid[32]; /* 32 = 11 character for "(suid = ) " + 20 character for ULONG_MAX + '\0' */ tag_suid[0] = '\0'; WallTimeSpec tss, tsr; - Bool ok_tss = swFALSE, ok_tsr = swFALSE; + Bool ok_tss = swFALSE, ok_tsr = swFALSE, ok_suid; + int progFileID = 0; // Value does not matter if SWNETCDF is not defined + int progVarID = 0; // Value does not matter if SWNETCDF is not defined + + #if defined(SWNETCDF) + progFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCprog]; + progVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCprog]; + #endif set_walltime(&tss, &ok_tss); @@ -231,7 +238,11 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], sw_init_logs(main_LogInfo->logfp, &local_LogInfo); SW_DOM_calc_ncSuid(SW_Domain, suid, ncSuid); - if(SW_DOM_CheckProgress(SW_Domain->DomainType, ncSuid)) { + + ok_suid = SW_DOM_CheckProgress(progFileID, progVarID, ncSuid, + &local_LogInfo); + + if(ok_suid && !local_LogInfo.stopRun) { nSims++; // Counter of simulation runs @@ -240,22 +251,20 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], SW_OutputPtrs, NULL, &local_LogInfo); SW_WT_TimeRun(tsr, ok_tsr, SW_WallTime); - if(local_LogInfo.stopRun) { - main_LogInfo->numDomainErrors++; // Counter of simulation units with error - - } else { + if(!local_LogInfo.stopRun) { // Set simulation run progress - SW_DOM_SetProgress(SW_Domain->DomainType, ncSuid); + SW_DOM_SetProgress(SW_Domain->DomainType, progFileID, + progVarID, ncSuid, &local_LogInfo); } + } - if (local_LogInfo.numWarnings > 0) { - main_LogInfo->numDomainWarnings++; // Counter of simulation units with warnings - } + if (local_LogInfo.numWarnings > 0) { + main_LogInfo->numDomainWarnings++; // Counter of simulation units with warnings + } - if (local_LogInfo.stopRun || local_LogInfo.numWarnings > 0) { - snprintf(tag_suid, 32, "(suid = %lu) ", suid + 1); - sw_write_warnings(tag_suid, &local_LogInfo); - } + if (local_LogInfo.stopRun || local_LogInfo.numWarnings > 0) { + snprintf(tag_suid, 32, "(suid = %lu) ", suid + 1); + sw_write_warnings(tag_suid, &local_LogInfo); } } diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 961da9f17..474a40b69 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -75,7 +75,14 @@ void SW_DOM_calc_nSUIDs(SW_DOMAIN* SW_Domain) { */ Bool SW_DOM_CheckProgress(int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo) { + #if defined(SWNETCDF) + return SW_NC_check_progress(progFileID, progVarID, ncSuid, LogInfo); + #else + (void) progFileID; + (void) progVarID; (void) ncSuid; + (void) LogInfo; + #endif // return TRUE (due to lack of capability to track progress) return swTRUE; @@ -258,12 +265,19 @@ void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * in relation to netCDFs * @param[in,out] LogInfo */ -void SW_DOM_SetProgress(char* domainType, unsigned long ncSuid[]) { - (void) domainType; void SW_DOM_SetProgress(const char* domType, int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo) { + + #if defined(SWNETCDF) + SW_NC_set_progress(domType, progFileID, progVarID, ncSuid, LogInfo); + #else + (void) progFileID; + (void) progVarID; (void) ncSuid; + (void) LogInfo; + (void) domType; + #endif } /** @@ -278,10 +292,18 @@ void SW_DOM_SetProgress(const char* domType, int progFileID, void SW_DOM_SimSet(SW_DOMAIN* SW_Domain, unsigned long userSUID, LOG_INFO* LogInfo) { + Bool progFound; unsigned long *startSimSet = &SW_Domain->startSimSet, *endSimSet = &SW_Domain->endSimSet, startSuid[2]; // 2 -> [y, x] or [0, s] + int progFileID = 0; // Value does not matter if SWNETCDF is not defined + int progVarID = 0; // Value does not matter if SWNETCDF is not defined + + #if defined(SWNETCDF) + progFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCprog]; + progVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCprog]; + #endif if(userSUID > 0) { if(userSUID > SW_Domain->nSUIDs) { @@ -300,8 +322,11 @@ void SW_DOM_SimSet(SW_DOMAIN* SW_Domain, unsigned long userSUID, for(*startSimSet = 0; *startSimSet < *endSimSet; (*startSimSet)++) { SW_DOM_calc_ncSuid(SW_Domain, *startSimSet, startSuid); - if(SW_DOM_CheckProgress(SW_Domain->DomainType, startSuid)) { - return; // Found start suid + progFound = SW_DOM_CheckProgress(progFileID, progVarID, + startSuid, LogInfo); + + if(progFound || LogInfo->stopRun) { + return; // Found start suid or error occurred } } } diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index d12253c06..5b4f9515b 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -395,6 +395,26 @@ static void get_single_uint_val(int ncFileID, int varID, size_t index[], "unsigned integer."); } } + +/** + * @brief Get a byte value from a variable + * + * @param[in] ncFileID Identifier of the open netCDF file to access + * @param[in] varID Identifier of the variable + * @param[in] varName Name of the variable to access + * @param[in] index Location of the value within the variable + * @param[out] value String buffer to hold the resulting value + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +static void get_single_byte_val(int ncFileID, int varID, size_t index[], + signed char* value, LOG_INFO* LogInfo) { + + if(nc_get_var1_schar(ncFileID, varID, index, value) != NC_NOERR) { + LogError(LogInfo, LOGERROR, "An error occurred when trying to " + "get a value from a variable of type byte"); + } +} + /** * @brief Get a dimension value from a given netCDF file * @@ -1982,6 +2002,11 @@ void SW_NC_set_progress(const char* domType, int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { + const signed char mark = 1; + size_t *count = (strcmp(domType, "s") == 0) ? (size_t[1]){1} : (size_t[2]){1, 1}; + + fill_netCDF_var_byte(progFileID, progVarID, &mark, ncSUID, count, LogInfo); + nc_sync(progFileID); } /** @@ -1997,6 +2022,11 @@ void SW_NC_set_progress(const char* domType, int progFileID, Bool SW_NC_check_progress(int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { + signed char progVal = 0, readyVal = 0; + + get_single_byte_val(progFileID, progVarID, ncSUID, &progVal, LogInfo); + + return (Bool) (!LogInfo->stopRun && progVal == readyVal); } /** From dab1827a56a7c3c21ca8d0e6fcae19ad4f73b738 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Fri, 5 Jan 2024 14:34:44 -0700 Subject: [PATCH 08/27] Update `get_dim_identifier()` arguments to use `const char*` --- src/SW_netCDF.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 5b4f9515b..930667ed6 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -247,7 +247,7 @@ static void nc_read_atts(SW_NETCDF* SW_netCDF, PATH_INFO* PathInfo, * @param[out] dimID Identifier of the dimension * @param[out] LogInfo Holds information on warnings and errors */ -static void get_dim_identifier(int ncFileID, char* dimName, int* dimID, +static void get_dim_identifier(int ncFileID, const char* dimName, int* dimID, LOG_INFO* LogInfo) { if(nc_inq_dimid(ncFileID, dimName, dimID) != NC_NOERR) { From 501e72bab992ca9db070a923cdb92242f6d4ac8d Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 09:44:46 -0500 Subject: [PATCH 09/27] Fix SW_NC_read(): new switch case was missing a break --- src/SW_netCDF.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 930667ed6..00d5d6d84 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -2132,6 +2132,7 @@ void SW_NC_read(SW_NETCDF* SW_netCDF, PATH_INFO* PathInfo, LOG_INFO* LogInfo) { case vNCprog: SW_netCDF->varNC[vNCprog] = Str_Dup(varName, LogInfo); SW_netCDF->InFilesNC[vNCprog] = Str_Dup(path, LogInfo); + break; default: LogError(LogInfo, LOGWARN, "Ignoring unknown key in %s, %s", MyFileName, key); From 5be7b2052615310f6963fa710d6898f0b41aca6b Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 09:46:41 -0500 Subject: [PATCH 10/27] Fix SW_CTL_RunSimSet(): numDomainErrors was no longer incremented if simulation run errored --- src/SW_Control.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/SW_Control.c b/src/SW_Control.c index a46f2b044..04fb3053d 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -211,6 +211,7 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], tag_suid[0] = '\0'; WallTimeSpec tss, tsr; Bool ok_tss = swFALSE, ok_tsr = swFALSE, ok_suid; + int progFileID = 0; // Value does not matter if SWNETCDF is not defined int progVarID = 0; // Value does not matter if SWNETCDF is not defined @@ -221,6 +222,7 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], set_walltime(&tss, &ok_tss); + /* Loop over suids in simulation set of domain */ for(suid = SW_Domain->startSimSet; suid < SW_Domain->endSimSet; suid++) { /* Check wall time against limit */ @@ -237,27 +239,34 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], LOG_INFO local_LogInfo; sw_init_logs(main_LogInfo->logfp, &local_LogInfo); + /* Check if suid needs to be simulated */ SW_DOM_calc_ncSuid(SW_Domain, suid, ncSuid); ok_suid = SW_DOM_CheckProgress(progFileID, progVarID, ncSuid, &local_LogInfo); if(ok_suid && !local_LogInfo.stopRun) { + /* Count simulation run */ + nSims++; - nSims++; // Counter of simulation runs - + /* Simulate suid */ set_walltime(&tsr, &ok_tsr); SW_CTL_run_sw(sw_template, SW_Domain, ncSuid, SW_OutputPtrs, NULL, &local_LogInfo); SW_WT_TimeRun(tsr, ok_tsr, SW_WallTime); + /* Report progress for suid */ if(!local_LogInfo.stopRun) { - // Set simulation run progress SW_DOM_SetProgress(SW_Domain->DomainType, progFileID, progVarID, ncSuid, &local_LogInfo); } } + /* Report errors and warnings for suid */ + if(local_LogInfo.stopRun) { + main_LogInfo->numDomainErrors++; // Counter of simulation units with error + } + if (local_LogInfo.numWarnings > 0) { main_LogInfo->numDomainWarnings++; // Counter of simulation units with warnings } @@ -268,6 +277,7 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], } } + /* Produce global error if all suids failed */ if (nSims == main_LogInfo->numDomainErrors) { LogError( main_LogInfo, From 217226fa0df105cbcd694cbf07c2d63f964187bd Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 10:32:35 -0500 Subject: [PATCH 11/27] progress: identify failed simulation runs - marking status of simulation runs as succeeded/failed - this signals that failed runs should not be simulated again, e.g., after a restart (only after the underlying problem has been resolved and those suids reset) - define progress status --- include/SW_Domain.h | 2 +- include/SW_netCDF.h | 2 +- src/SW_Control.c | 12 ++++++------ src/SW_Domain.c | 8 +++++--- src/SW_netCDF.c | 19 ++++++++++++------- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/include/SW_Domain.h b/include/SW_Domain.h index 042c1799c..5ad3baec1 100644 --- a/include/SW_Domain.h +++ b/include/SW_Domain.h @@ -17,7 +17,7 @@ Bool SW_DOM_CheckProgress(int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo); void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); -void SW_DOM_SetProgress(const char* domType, int progFileID, +void SW_DOM_SetProgress(Bool success, const char* domType, int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo); void SW_DOM_SimSet(SW_DOMAIN* SW_Domain, unsigned long userSUID, diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index a4b6d73bd..6dc28f2b9 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -28,7 +28,7 @@ void SW_NC_create_template(const char* domFile, int domFileID, const char* attNames[], const char* attVals[], int numAtts, Bool isInput, const char* freq, LOG_INFO* LogInfo); void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); -void SW_NC_set_progress(const char* domType, int progFileID, +void SW_NC_set_progress(Bool success, const char* domType, int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo); Bool SW_NC_check_progress(int progFileID, int progVarID, diff --git a/src/SW_Control.c b/src/SW_Control.c index 04fb3053d..f0f229f0b 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -256,10 +256,9 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], SW_WT_TimeRun(tsr, ok_tsr, SW_WallTime); /* Report progress for suid */ - if(!local_LogInfo.stopRun) { - SW_DOM_SetProgress(SW_Domain->DomainType, progFileID, - progVarID, ncSuid, &local_LogInfo); - } + SW_DOM_SetProgress(!local_LogInfo.stopRun, + SW_Domain->DomainType, progFileID, + progVarID, ncSuid, &local_LogInfo); } /* Report errors and warnings for suid */ @@ -278,11 +277,12 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], } /* Produce global error if all suids failed */ - if (nSims == main_LogInfo->numDomainErrors) { + if (nSims > 0 && nSims == main_LogInfo->numDomainErrors) { LogError( main_LogInfo, LOGERROR, - "All simulated units produced errors." + "All simulated units (n = %zu) produced errors.", + nSims ); } diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 474a40b69..5839968d5 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -255,8 +255,9 @@ void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { } /** - * @brief Mark a completed suid in progress netCDF + * @brief Mark completion status of simulation run * + * @param[in] success Did simulation run succeed or fail? * @param[in] domType Type of domain in which simulations are running * (gridcell/sites) * @param[in] progFileID Identifier of the progress netCDF file @@ -265,13 +266,14 @@ void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * in relation to netCDFs * @param[in,out] LogInfo */ -void SW_DOM_SetProgress(const char* domType, int progFileID, +void SW_DOM_SetProgress(Bool success, const char* domType, int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo) { #if defined(SWNETCDF) - SW_NC_set_progress(domType, progFileID, progVarID, ncSuid, LogInfo); + SW_NC_set_progress(success, domType, progFileID, progVarID, ncSuid, LogInfo); #else + (void) success (void) progFileID; (void) progVarID; (void) ncSuid; diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 00d5d6d84..23d38bf85 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -19,6 +19,11 @@ #define NUM_NC_IN_KEYS 2 // Number of possible keys within `files_nc.in` #define NUM_ATT_IN_KEYS 25 // Number of possible keys within `attributes_nc.in` +#define PRGRSS_READY ((signed char)0) // SUID is ready for simulation +#define PRGRSS_DONE ((signed char)1) // SUID has successfully been simulated +#define PRGRSS_FAIL ((signed char)-1) // SUID failed to simulate + + /* =================================================== */ /* Local Function Definitions */ /* --------------------------------------------------- */ @@ -646,7 +651,6 @@ static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { int domVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCdom]; int progVarID = SW_Domain->netCDFInfo.ncVarIDs[vNCprog]; - signed char readyVal = 0; unsigned int domStatus; unsigned long suid, ncSuid[2], nSUIDs = SW_Domain->nSUIDs; unsigned long nDimY = SW_Domain->nDimY, nDimX = SW_Domain->nDimX; @@ -672,7 +676,7 @@ static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { return; // Exit function prematurely due to error } - vals[suid] = (domStatus == NC_FILL_UINT) ? NC_FILL_BYTE : readyVal; + vals[suid] = (domStatus == NC_FILL_UINT) ? NC_FILL_BYTE : PRGRSS_READY; } fill_netCDF_var_byte(progFileID, progVarID, vals, start, count, LogInfo); @@ -1988,8 +1992,9 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { } /** - * @brief Mark a site/gridcell as completed in the progress file + * @brief Mark a site/gridcell as completed (success/fail) in the progress file * + * @param[in] success Did simulation run succeed or fail? * @param[in] domType Type of domain in which simulations are running * (gridcell/sites) * @param[in] progFileID Identifier of the progress netCDF file @@ -1998,11 +2003,11 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * to get data from netCDF * @param[in,out] LogInfo Holds information dealing with logfile output */ -void SW_NC_set_progress(const char* domType, int progFileID, +void SW_NC_set_progress(Bool success, const char* domType, int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { - const signed char mark = 1; + const signed char mark = (success) ? PRGRSS_DONE : PRGRSS_FAIL; size_t *count = (strcmp(domType, "s") == 0) ? (size_t[1]){1} : (size_t[2]){1, 1}; fill_netCDF_var_byte(progFileID, progVarID, &mark, ncSUID, count, LogInfo); @@ -2022,11 +2027,11 @@ void SW_NC_set_progress(const char* domType, int progFileID, Bool SW_NC_check_progress(int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { - signed char progVal = 0, readyVal = 0; + signed char progVal = 0; get_single_byte_val(progFileID, progVarID, ncSUID, &progVal, LogInfo); - return (Bool) (!LogInfo->stopRun && progVal == readyVal); + return (Bool) (!LogInfo->stopRun && progVal == PRGRSS_READY); } /** From 2e90c24ac4b8f71d43b9e4192d0bca640135f781 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 11:02:55 -0500 Subject: [PATCH 12/27] progress.nc gains attributes "flag_values" and "flag_meanings" - flag_values: list of possible flag values - flag_meanings: a string whose value is a blank separated list of descriptive words or phrases, one for each flag value --- src/SW_netCDF.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 23d38bf85..2f708d219 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -568,15 +568,16 @@ static void fill_netCDF_var_double(int ncFileID, int varID, double values[], * @brief Write a local attribute of type byte * * @param[in] attName Name of the attribute to create - * @param[in] attVal Value to write out + * @param[in] attVal Attribute value(s) to write out * @param[in] varID Identifier of the variable to add the attribute to * @param[in] ncFileID Identifier of the open netCDF file to write the attribute to + * @param[in] numVals Number of values to write to the single attribute * @param[out] LogInfo Holds information dealing with logfile output */ -static void write_byte_att(const char* attName, const signed char attVal, - int varID, int ncFileID, LOG_INFO* LogInfo) { +static void write_byte_att(const char* attName, const signed char* attVal, + int varID, int ncFileID, int numVals, LOG_INFO* LogInfo) { - if(nc_put_att_schar(ncFileID, varID, attName, NC_BYTE, 1, &attVal) != NC_NOERR) { + if(nc_put_att_schar(ncFileID, varID, attName, NC_BYTE, numVals, attVal) != NC_NOERR) { LogError(LogInfo, LOGERROR, "Could not create new attribute %s", attName); } @@ -624,7 +625,7 @@ static void write_str_att(const char* attName, const char* attStr, * @brief Write an attribute of type double to a variable * * @param[in] attName Name of the attribute to create - * @param[in] attVal Attribute value to write out + * @param[in] attVal Attribute value(s) to write out * @param[in] varID Identifier of the variable to add the attribute to * (Note: NC_GLOBAL is acceptable and is a global attribute of the netCDF file) * @param[in] ncFileID Identifier of the open netCDF file to write the attribute to @@ -1953,7 +1954,10 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { "coordinates"}; const char* attVals[] = {"simulation progress", "1", grid_map, coord}; const int numAtts = 4; + int numValsToWrite; const signed char fillVal = NC_FILL_BYTE; + const signed char flagVals[] = {PRGRSS_FAIL, PRGRSS_READY, PRGRSS_DONE}; + const char* flagMeanings = "simulation_error ready_to_simulate simulation_complete"; const char* varName = SW_netCDF->varNC[vNCprog]; const char* freq = "fx"; @@ -1974,17 +1978,31 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { return; // Exit function prematurely due to error } - // Write out the attribute "_FillValue" to the progress variable get_var_identifier(*progFileID, varName, progVarID, LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } - write_byte_att("_FillValue", fillVal, *progVarID, *progFileID, LogInfo); + // Add attribute "_FillValue" to the progress variable + numValsToWrite = 1; + write_byte_att("_FillValue", &fillVal, *progVarID, *progFileID, numValsToWrite, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + // Add attributes "flag_values" and "flag_meanings" + numValsToWrite = 3; + write_byte_att("flag_values", flagVals, *progVarID, *progFileID, numValsToWrite, LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } + write_str_att("flag_meanings", flagMeanings, *progVarID, *progFileID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + nc_enddef(*progFileID); fill_prog_netCDF_vals(SW_Domain, LogInfo); From fe4b1d6ebb89dd11840da4ec5de6b5f8c2f80bd2 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 12:02:46 -0500 Subject: [PATCH 13/27] Fix missing ";" in non-SWNETCDF code - I introduced the mistake in commit 217226fa0df105cbcd694cbf07c2d63f964187bd --- src/SW_Domain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 5839968d5..295e2921d 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -273,7 +273,7 @@ void SW_DOM_SetProgress(Bool success, const char* domType, int progFileID, #if defined(SWNETCDF) SW_NC_set_progress(success, domType, progFileID, progVarID, ncSuid, LogInfo); #else - (void) success + (void) success; (void) progFileID; (void) progVarID; (void) ncSuid; From 0cbaa0484cf264ac22e7cd2e5960050d6a5b8ec2 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 12:17:53 -0500 Subject: [PATCH 14/27] Fix Bool vs bool conversion for C++ gtests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - C++ code error: cannot convert ‘bool’ to ‘Bool’, i.e., `!local_LogInfo.stopRun` is a "bool" and not a "Bool" as SW_DOM_SetProgress() was expecting --> invert logic, i.e., pass error status directly as 'Bool' --- include/SW_Domain.h | 2 +- include/SW_netCDF.h | 2 +- src/SW_Control.c | 2 +- src/SW_Domain.c | 8 ++++---- src/SW_netCDF.c | 6 +++--- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/SW_Domain.h b/include/SW_Domain.h index 5ad3baec1..33b2a6c3b 100644 --- a/include/SW_Domain.h +++ b/include/SW_Domain.h @@ -17,7 +17,7 @@ Bool SW_DOM_CheckProgress(int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo); void SW_DOM_CreateProgress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); -void SW_DOM_SetProgress(Bool success, const char* domType, int progFileID, +void SW_DOM_SetProgress(Bool isFailure, const char* domType, int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo); void SW_DOM_SimSet(SW_DOMAIN* SW_Domain, unsigned long userSUID, diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index 6dc28f2b9..e5db14c54 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -28,7 +28,7 @@ void SW_NC_create_template(const char* domFile, int domFileID, const char* attNames[], const char* attVals[], int numAtts, Bool isInput, const char* freq, LOG_INFO* LogInfo); void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); -void SW_NC_set_progress(Bool success, const char* domType, int progFileID, +void SW_NC_set_progress(Bool isFailure, const char* domType, int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo); Bool SW_NC_check_progress(int progFileID, int progVarID, diff --git a/src/SW_Control.c b/src/SW_Control.c index f0f229f0b..931bb22c0 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -256,7 +256,7 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], SW_WT_TimeRun(tsr, ok_tsr, SW_WallTime); /* Report progress for suid */ - SW_DOM_SetProgress(!local_LogInfo.stopRun, + SW_DOM_SetProgress(local_LogInfo.stopRun, SW_Domain->DomainType, progFileID, progVarID, ncSuid, &local_LogInfo); } diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 295e2921d..f7fe8c59b 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -257,7 +257,7 @@ void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { /** * @brief Mark completion status of simulation run * - * @param[in] success Did simulation run succeed or fail? + * @param[in] isFailure Did simulation run fail or succeed? * @param[in] domType Type of domain in which simulations are running * (gridcell/sites) * @param[in] progFileID Identifier of the progress netCDF file @@ -266,14 +266,14 @@ void SW_DOM_read(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * in relation to netCDFs * @param[in,out] LogInfo */ -void SW_DOM_SetProgress(Bool success, const char* domType, int progFileID, +void SW_DOM_SetProgress(Bool isFailure, const char* domType, int progFileID, int progVarID, unsigned long ncSuid[], LOG_INFO* LogInfo) { #if defined(SWNETCDF) - SW_NC_set_progress(success, domType, progFileID, progVarID, ncSuid, LogInfo); + SW_NC_set_progress(isFailure, domType, progFileID, progVarID, ncSuid, LogInfo); #else - (void) success; + (void) isFailure; (void) progFileID; (void) progVarID; (void) ncSuid; diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 2f708d219..d21b3c65e 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -2012,7 +2012,7 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { /** * @brief Mark a site/gridcell as completed (success/fail) in the progress file * - * @param[in] success Did simulation run succeed or fail? + * @param[in] isFailure Did simulation run fail or succeed? * @param[in] domType Type of domain in which simulations are running * (gridcell/sites) * @param[in] progFileID Identifier of the progress netCDF file @@ -2021,11 +2021,11 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { * to get data from netCDF * @param[in,out] LogInfo Holds information dealing with logfile output */ -void SW_NC_set_progress(Bool success, const char* domType, int progFileID, +void SW_NC_set_progress(Bool isFailure, const char* domType, int progFileID, int progVarID, unsigned long ncSUID[], LOG_INFO* LogInfo) { - const signed char mark = (success) ? PRGRSS_DONE : PRGRSS_FAIL; + const signed char mark = (isFailure) ? PRGRSS_FAIL : PRGRSS_DONE; size_t *count = (strcmp(domType, "s") == 0) ? (size_t[1]){1} : (size_t[2]){1, 1}; fill_netCDF_var_byte(progFileID, progVarID, &mark, ncSUID, count, LogInfo); From 0ca81ba911746bb732edacce7a8ebc875e2afd92 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 12:25:49 -0500 Subject: [PATCH 15/27] Fix buffer overflow in SW_NC_read_inputs() - recent code development added "progress.nc" and thus incremented SW_NVARNC: this caused a buffer overflow in SW_NC_read_inputs(): fileNum was in 0 1 but numVals[] remained an array of length 1 --- src/SW_netCDF.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index d21b3c65e..9c4509bc6 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -2068,6 +2068,7 @@ void SW_NC_read_inputs(SW_ALL* sw, SW_DOMAIN* SW_Domain, size_t ncSUID[], int file, varNum; Bool domTypeS = Str_CompareI(SW_Domain->DomainType, "s") == 0; + const int numInFilesNC = 1; const int numDomVals = 2; const int numVals[] = {numDomVals}; const int ncFileIDs[] = {SW_Domain->netCDFInfo.ncFileIDs[vNCdom]}; @@ -2084,7 +2085,7 @@ void SW_NC_read_inputs(SW_ALL* sw, SW_DOMAIN* SW_Domain, size_t ncSUID[], For the domain type "xy", the index of the variable "y" is the first in "ncSUID" and the index of the variable "x" is the second in "ncSUID" */ - for(file = 0; file < SW_NVARNC; file++) { + for(file = 0; file < numInFilesNC; file++) { for(varNum = 0; varNum < numVals[file]; varNum++) { ncIndex = (domTypeS) ? 0 : varNum % 2; From b10a6dd8fdc53b2ff3f711580d0987bdb172f3e8 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Sun, 7 Jan 2024 12:35:08 -0500 Subject: [PATCH 16/27] Update NEWS to describe "progress" tracking --- NEWS.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 8369186bc..707b9b307 100644 --- a/NEWS.md +++ b/NEWS.md @@ -29,6 +29,11 @@ * For `"netCDF"`-based SOILWAT2, information about the `"domain"` (i.e., simulation units and their geographic locations) is obtained from `"domain.nc"` (#361; @N1ckP3rsl3y, @dschlaep). + * For `"netCDF"`-based SOILWAT2, simulation progress (success/failure) is + tracked by `"progress.nc"` (#387; @N1ckP3rsl3y, @dschlaep); + progress tracking makes re-starts after partial completion of the + simulation set by an earlier execution possible. + * Tests now utilize the same template/deep-copy approach (@dschlaep), i.e., input files from `test/example/` populate a `"template"` and @@ -79,7 +84,7 @@ * New input directory `"Input_nc/"` that describes `"netCDF"`-based inputs (paths provided by new entries in `"files.in"`). * New text input file `"files_nc.in"` that lists for each input purpose - (currently, only `"domain"` is implemented) + (currently, `"domain"` and `"progress"` are implemented) the path to the `"netCDF"` input file and associated variable name. * New text input file `"attribues_nc.in"` to provide global attributes and a geographic (and optionally a projected) `"CRS"` (coordinate reference system) @@ -87,6 +92,9 @@ * A user provided `"domain.nc"` that describes the simulation `"domain"`. Specifications must be consistent with `"domain.in"`. If absent, a template is automatically generated based on `"domain.in"`. +* A user provided `"progress.nc"` that describes the simulation `"progress"`. + Specifications must be consistent with `"domain.nc"`. + If absent, it is automatically generated based on `"domain.nc"`. # SOILWAT2 v7.2.0 From 42cc205f02bc4945e061de93de4e6dae01aeed76 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Mon, 8 Jan 2024 16:12:36 -0700 Subject: [PATCH 17/27] Allow for progress variable to be within domain netCDF - Rename `SW_NC_open_files()` to `SW_NC_open_dom_prog_files()` to show it only opens the domain and progress files - `SW_NC_open_dom_prog_files()` * Opens the domain and progress files in write mode * Handles the case where the progress variable may be in its own file or in the domain file and the domain file does or does not have the variable - `SW_NC_create_progress()` * Detects if a new progress template needs to be created (creates a template with `SW_NC_create_template()` and fills byte attributes) * Detects if a progress variable needs to be created (creates a new variable with `create_full_var()` and fills byte attributes) * Detects if a progress variable already exists somewhere (does nothing) * Does not write out progress variable attributes if the variable existed before the function call - New local function `create_full_var()` * Moved the variable creation within `SW_NC_create_template()` to this function * Calculates dimensions to write to variable and their IDs * Writes given attributes to the variable * Can be used to add variables into a template or add a variable when a file is already well-defined (e.g., adding a progress variable to domain) - `SW_NC_create_template()` * Moved dimension calculations/attribute writing/variable creation to `create_full_var()` --- include/SW_netCDF.h | 2 +- src/SW_Control.c | 2 +- src/SW_netCDF.c | 219 ++++++++++++++++++++++++++++---------------- 3 files changed, 144 insertions(+), 79 deletions(-) diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index e5db14c54..3337dc527 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -39,7 +39,7 @@ void SW_NC_check_input_files(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo); void SW_NC_read(SW_NETCDF* SW_netCDF, PATH_INFO* PathInfo, LOG_INFO* LogInfo); void SW_NC_init_ptrs(SW_NETCDF* SW_netCDF); void SW_NC_deconstruct(SW_NETCDF* SW_netCDF); -void SW_NC_open_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo); +void SW_NC_open_dom_prog_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo); void SW_NC_close_files(SW_NETCDF* SW_netCDF); #ifdef __cplusplus diff --git a/src/SW_Control.c b/src/SW_Control.c index 931bb22c0..82a7440b4 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -383,7 +383,7 @@ void SW_CTL_setup_domain(unsigned long userSUID, } // Open necessary netCDF input files and check for consistency with domain - SW_NC_open_files(&SW_Domain->netCDFInfo, LogInfo); + SW_NC_open_dom_prog_files(&SW_Domain->netCDFInfo, LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 9c4509bc6..ab435d992 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1508,6 +1508,73 @@ static void fill_netCDF_with_invariants(SW_NETCDF* SW_netCDF, char* domType, isInputFile, LogInfo); } +/** + * @brief Create a new variable by calculating the dimensions + * and writing attributes + * + * @param[in] ncFileID Identifier of the netCDF file + * @param[in] newVarType Type of the variable to create + * @param[in] timeSize Size of "time" dimension + * @param[in] vertSize Size of "vertical" dimension + * @param[in] varName Name of variable to write + * @param[in] attNames Attribute names that the new variable will contain + * @param[in] attVals Attribute values that the new variable will contain + * @param[in] numAtts Number of attributes being sent in + * @param[in,out] LogInfo Holds information dealing with logfile output +*/ +static void create_full_var(int* ncFileID, int newVarType, + unsigned long timeSize, unsigned long vertSize, const char* varName, + const char* attNames[], const char* attVals[], int numAtts, + LOG_INFO* LogInfo) { + + int dimArrSize = 0, index, varID = 0; + int dimIDs[4]; // Maximum expected number of dimensions + Bool siteDimExists = dimExists("site", *ncFileID); + const char* latName = (dimExists("lat", *ncFileID)) ? "lat" : "y"; + const char* lonName = (dimExists("lon", *ncFileID)) ? "lon" : "x"; + int numConstDims = (siteDimExists) ? 1 : 2; + const char* thirdDim = (siteDimExists) ? "site" : latName; + const char* constDimNames[] = {thirdDim, lonName}; + const char* timeVertNames[] = {"time", "vertical"}; + int timeVertVals[] = {timeSize, vertSize}, numTimeVertVals = 2; + + for(index = 0; index < numTimeVertVals; index++) { + if(timeVertVals[index] > 0) { + create_netCDF_dim(timeVertNames[index], timeSize, ncFileID, + &dimIDs[dimArrSize], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + dimArrSize++; + } + } + + for(index = 0; index < numConstDims; index++) { + get_dim_identifier(*ncFileID, constDimNames[index], + &dimIDs[dimArrSize], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + dimArrSize++; + } + + for(index = 0; index < numAtts; index++) { + write_str_att(attNames[index], attVals[index], + varID, *ncFileID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + } + + create_netCDF_var(&varID, varName, dimIDs, ncFileID, newVarType, + dimArrSize, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } +} + /* =================================================== */ /* Global Function Definitions */ /* --------------------------------------------------- */ @@ -1867,17 +1934,9 @@ void SW_NC_create_template(const char* domFile, int domFileID, const char* attNames[], const char* attVals[], int numAtts, Bool isInput, const char* freq, LOG_INFO* LogInfo) { - int dimArrSize = 0, index, varID = 0; - int dimIDs[4]; // Maximum expected number of dimensions Bool siteDimExists = dimExists("site", domFileID); - const char* latName = (dimExists("lat", domFileID)) ? "lat" : "y"; - const char* lonName = (dimExists("lon", domFileID)) ? "lon" : "x"; const char* domType = (siteDimExists) ? "s" : "xy"; - int numConstDims = (siteDimExists) ? 1 : 2; - const char* thirdDim = (siteDimExists) ? "site" : latName; - const char* constDimNames[] = {thirdDim, lonName}; - const char* timeVertNames[] = {"time", "vertical"}; - int timeVertVals[] = {timeSize, vertSize}, numTimeVertVals = 2; + CopyFile(domFile, fileName, LogInfo); if(LogInfo->stopRun) { @@ -1890,46 +1949,15 @@ void SW_NC_create_template(const char* domFile, int domFileID, return; // Exit function prematurely due to error } - for(index = 0; index < numTimeVertVals; index++) { - if(timeVertVals[index] > 0) { - create_netCDF_dim(timeVertNames[index], timeSize, newFileID, - &dimIDs[dimArrSize], LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error - } - - dimArrSize++; - } - } - - for(index = 0; index < numConstDims; index++) { - get_dim_identifier(*newFileID, constDimNames[index], - &dimIDs[dimArrSize], LogInfo); + if(!varExists(*newFileID, varName)) { + create_full_var(newFileID, newVarType, timeSize, vertSize, varName, + attNames, attVals, numAtts, LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } - - dimArrSize++; - } - - create_netCDF_var(&varID, varName, dimIDs, newFileID, newVarType, - dimArrSize, LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error } update_netCDF_global_atts(newFileID, domType, freq, isInput, LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error - } - - for(index = 0; index < numAtts; index++) { - write_str_att(attNames[index], attVals[index], - varID, *newFileID, LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error - } - } } /** @@ -1958,7 +1986,7 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { const signed char fillVal = NC_FILL_BYTE; const signed char flagVals[] = {PRGRSS_FAIL, PRGRSS_READY, PRGRSS_DONE}; const char* flagMeanings = "simulation_error ready_to_simulate simulation_complete"; - const char* varName = SW_netCDF->varNC[vNCprog]; + const char* progVarName = SW_netCDF->varNC[vNCprog]; const char* freq = "fx"; int domFileID = SW_netCDF->ncFileIDs[vNCdom]; @@ -1967,39 +1995,61 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { const char* progFileName = SW_netCDF->InFilesNC[vNCprog]; int* progVarID = &SW_netCDF->ncVarIDs[vNCprog]; - if(FileExists(SW_Domain->netCDFInfo.InFilesNC[vNCprog])) { - SW_NC_check(SW_Domain, *progFileID, progFileName, LogInfo); - } else { - SW_NC_create_template(domFileName, domFileID, progFileName, - progFileID, NC_BYTE, 0, 0, varName, - attNames, attVals, numAtts, swFALSE, freq, - LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error - } + Bool progFileIsDom = (Bool) (strcmp(progFileName, domFileName) == 0); + Bool progFileExists = FileExists(progFileName); + Bool progVarExists = varExists(*progFileID, progVarName); + Bool createOrModFile = !progFileExists || (progFileIsDom && !progVarExists); - get_var_identifier(*progFileID, varName, progVarID, LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error + /* + See if the progress variable exists within it's file, also handling + the case where the progress variable is in the domain netCDF + + In addition to making sure the file exists, make sure the progress + variable is present + */ + if(createOrModFile) { + + if(progFileExists) { + nc_redef(*progFileID); + + create_full_var(progFileID, NC_BYTE, 0, 0, progVarName, + attNames, attVals, numAtts, LogInfo); + } else { + SW_NC_create_template(domFileName, domFileID, progFileName, + progFileID, NC_BYTE, 0, 0, progVarName, attNames, attVals, + numAtts, swFALSE, freq, LogInfo); } - // Add attribute "_FillValue" to the progress variable - numValsToWrite = 1; - write_byte_att("_FillValue", &fillVal, *progVarID, *progFileID, numValsToWrite, LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } - // Add attributes "flag_values" and "flag_meanings" - numValsToWrite = 3; - write_byte_att("flag_values", flagVals, *progVarID, *progFileID, numValsToWrite, LogInfo); + get_var_identifier(*progFileID, progVarName, progVarID, LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } - write_str_att("flag_meanings", flagMeanings, *progVarID, *progFileID, LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error + // If the progress existed before this function was called, + // do not set the new attributes + if(!progVarExists) { + // Add attribute "_FillValue" to the progress variable + numValsToWrite = 1; + write_byte_att("_FillValue", &fillVal, *progVarID, *progFileID, numValsToWrite, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + // Add attributes "flag_values" and "flag_meanings" + numValsToWrite = 3; + write_byte_att("flag_values", flagVals, *progVarID, *progFileID, numValsToWrite, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + write_str_att("flag_meanings", flagMeanings, *progVarID, *progFileID, LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } } @@ -2265,30 +2315,45 @@ void SW_NC_deconstruct(SW_NETCDF* SW_netCDF) { * @param[out] LogInfo Struct of type SW_NETCDF holding constant * netCDF file information */ -void SW_NC_open_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo) { - int fileNum, openType, *fileID; - char* fileName; - - for(fileNum = 0; fileNum < SW_NVARNC; fileNum++) { +void SW_NC_open_dom_prog_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo) { + int fileNum, openType = NC_WRITE, *fileID; + char* fileName, *domFile = SW_netCDF->InFilesNC[vNCdom]; + char* progFile = SW_netCDF->InFilesNC[vNCprog]; + Bool progFileDomain = (Bool) (strcmp(domFile, progFile) == 0); + + // Open the domain/progress netCDF + for(fileNum = vNCdom; fileNum <= vNCprog; fileNum++) { fileName = SW_netCDF->InFilesNC[fileNum]; fileID = &SW_netCDF->ncFileIDs[fileNum]; if(FileExists(fileName)) { - openType = (fileNum == vNCprog) ? NC_WRITE : NC_NOWRITE; - if(nc_open(fileName, openType, fileID) != NC_NOERR) { LogError(LogInfo, LOGERROR, "An error occurred when opening %s.", fileName); return; // Exit function prematurely due to error } - get_var_identifier(*fileID, SW_netCDF->varNC[fileNum], - &SW_netCDF->ncVarIDs[fileNum], LogInfo); - if(LogInfo->stopRun) { - return; // Exit function prematurely due to error + /* + Get the ID for the domain variable and the progress variable if + it is not in the domain netCDF or it exists in the domain netCDF + */ + if(fileNum == vNCdom || !progFileDomain || + varExists(*fileID, SW_netCDF->varNC[fileNum])) { + + get_var_identifier(*fileID, SW_netCDF->varNC[fileNum], + &SW_netCDF->ncVarIDs[fileNum], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } } } } + + // Make sure the correct variables are present + if(progFileDomain) { + nc_close(SW_netCDF->ncFileIDs[vNCprog]); + SW_netCDF->ncFileIDs[vNCprog] = SW_netCDF->ncFileIDs[vNCdom]; + } } /** From 4b4e01d2c928991208595c4a492b1f3cc6f02693 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Mon, 8 Jan 2024 16:42:28 -0700 Subject: [PATCH 18/27] Add back progress netCDF checking --- src/SW_netCDF.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index ab435d992..a5718ac28 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -2001,13 +2001,17 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { Bool createOrModFile = !progFileExists || (progFileIsDom && !progVarExists); /* + If the progress file is not to be created or modified, check it + See if the progress variable exists within it's file, also handling the case where the progress variable is in the domain netCDF In addition to making sure the file exists, make sure the progress variable is present */ - if(createOrModFile) { + if(!createOrModFile) { + SW_NC_check(SW_Domain, *progFileID, progFileName, LogInfo); + } else { if(progFileExists) { nc_redef(*progFileID); From 3d28889e5d069aca2501d83595ac79daa37cbf89 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 9 Jan 2024 08:46:19 -0500 Subject: [PATCH 19/27] Clarify comments and documentation for domain/progress variables/files --- src/SW_netCDF.c | 17 +++++++++++------ tests/example/Input_nc/files_nc.in | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index a5718ac28..44a5c1a9a 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -531,7 +531,7 @@ static void fill_netCDF_var_uint(int ncFileID, int varID, unsigned int values[], * @param[in] startIndices Specification of where the C-provided netCDF * should start writing values within the specified variable * @param[in] count How many values to write into the given variable - * @param[out] LogInfo Holds information dealing with logfile output + * @param[out] LogInfo Holds information on warnings and errors */ static void fill_netCDF_var_byte(int ncFileID, int varID, const signed char values[], size_t startIndices[], size_t count[], @@ -572,7 +572,7 @@ static void fill_netCDF_var_double(int ncFileID, int varID, double values[], * @param[in] varID Identifier of the variable to add the attribute to * @param[in] ncFileID Identifier of the open netCDF file to write the attribute to * @param[in] numVals Number of values to write to the single attribute - * @param[out] LogInfo Holds information dealing with logfile output + * @param[out] LogInfo Holds information on warnings and errors */ static void write_byte_att(const char* attName, const signed char* attVal, int varID, int ncFileID, int numVals, LOG_INFO* LogInfo) { @@ -2312,12 +2312,15 @@ void SW_NC_deconstruct(SW_NETCDF* SW_netCDF) { } /** - * @brief Open all netCDF files that should be open throughout the program + * @brief Open netCDF file(s) that contain(s) domain and progress variables + * + * These files are kept open during simulations + * * to read geographic coordinates from the domain + * * to identify and update progress * * @param[in,out] SW_netCDF Struct of type SW_NETCDF holding constant * netCDF file information - * @param[out] LogInfo Struct of type SW_NETCDF holding constant - * netCDF file information + * @param[out] LogInfo Holds information on warnings and errors */ void SW_NC_open_dom_prog_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo) { int fileNum, openType = NC_WRITE, *fileID; @@ -2353,7 +2356,9 @@ void SW_NC_open_dom_prog_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo) { } } - // Make sure the correct variables are present + // If the progress variable is contained in the domain netCDF, then + // close the (redundant) progress file identifier + // and use instead the (equivalent) domain file identifier if(progFileDomain) { nc_close(SW_netCDF->ncFileIDs[vNCprog]); SW_netCDF->ncFileIDs[vNCprog] = SW_netCDF->ncFileIDs[vNCdom]; diff --git a/tests/example/Input_nc/files_nc.in b/tests/example/Input_nc/files_nc.in index 46911be56..940593a56 100644 --- a/tests/example/Input_nc/files_nc.in +++ b/tests/example/Input_nc/files_nc.in @@ -6,4 +6,4 @@ # This convention eliminates the possibility of incorrect reads due to line dependencies. domain domain Input_nc/domain.nc -progress progress Input_nc/progress.nc \ No newline at end of file +progress progress Input_nc/progress.nc # Note: progress can be a separate file or the same as domain From ae9dd5991abc713037185346fb777f847e40160f Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 9 Jan 2024 09:19:42 -0500 Subject: [PATCH 20/27] fill_prog_netCDF_vals(): free allocated memory --- src/SW_netCDF.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 44a5c1a9a..b5dd3a792 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -657,14 +657,14 @@ static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { unsigned long nDimY = SW_Domain->nDimY, nDimX = SW_Domain->nDimX; int progFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCprog]; int domFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCdom]; - signed char* vals = (signed char*)Mem_Malloc(nSUIDs * sizeof(signed char), - "fill_prog_netCDF_vals()", - LogInfo); size_t* start = (strcmp(SW_Domain->DomainType, "s") == 0) ? (size_t[1]){0} : (size_t[2]){0, 0}; size_t* count = (strcmp(SW_Domain->DomainType, "s") == 0) ? (size_t[1]){nSUIDs} : (size_t[2]){nDimY, nDimX}; + signed char* vals = (signed char*)Mem_Malloc(nSUIDs * sizeof(signed char), + "fill_prog_netCDF_vals()", + LogInfo); if(LogInfo->stopRun) { return; // Exit function prematurely due to error } @@ -674,7 +674,7 @@ static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { get_single_uint_val(domFileID, domVarID, ncSuid, &domStatus, LogInfo); if(LogInfo->stopRun) { - return; // Exit function prematurely due to error + goto freeMem; // Exit function prematurely due to error } vals[suid] = (domStatus == NC_FILL_UINT) ? NC_FILL_BYTE : PRGRSS_READY; @@ -682,6 +682,11 @@ static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { fill_netCDF_var_byte(progFileID, progVarID, vals, start, count, LogInfo); nc_sync(progFileID); + + // Free allocated memory + freeMem: { + free(vals); + } } /** From 7fd06e91ca8949667175bc940050861df8c4dfb8 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Mon, 8 Jan 2024 14:14:00 -0500 Subject: [PATCH 21/27] Allow user-specified hostname and username to replace automatic values --- doc/additional_pages/A_SOILWAT2_user_guide.md | 5 +++++ makefile | 5 +++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/doc/additional_pages/A_SOILWAT2_user_guide.md b/doc/additional_pages/A_SOILWAT2_user_guide.md index 287632ea7..8d1fadcc5 100644 --- a/doc/additional_pages/A_SOILWAT2_user_guide.md +++ b/doc/additional_pages/A_SOILWAT2_user_guide.md @@ -122,6 +122,11 @@ on your side. CPPFLAGS=-DSWNETCDF NC_CFLAGS="-I/path/to/include" NC_LIBS="-L/path/to/lib" make ``` + * User-specified username and hostname, e.g., +```{.sh} + USERNAME=nobody HOSTNAME=nowhere make +``` +
diff --git a/makefile b/makefile index c81d96c6c..6f0a4ae16 100644 --- a/makefile +++ b/makefile @@ -80,10 +80,11 @@ SHELL = /bin/sh #------ Identification SW2_VERSION := "$(shell git describe --abbrev=7 --dirty --always --tags)" -HOSTNAME := "$(shell uname -sn)" +HOSTNAME ?= "$(shell uname -sn)" +USERNAME ?= "$(USER)" sw_info := -DSW2_VERSION=\"$(SW2_VERSION)\" \ - -DUSERNAME=\"$(USER)\" \ + -DUSERNAME=\"$(USERNAME)\" \ -DHOSTNAME=\"$(HOSTNAME)\" From 15739591101f33c27716948f726b0f5422e4a746 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 9 Jan 2024 13:28:43 -0500 Subject: [PATCH 22/27] New timeStringISO8601() - timeStringISO8601(): string with current date and time in UTC formatted according to ISO 8601 --- include/Times.h | 1 + src/SW_netCDF.c | 6 ++---- src/Times.c | 12 ++++++++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/Times.h b/include/Times.h index 4b32cb4d3..07cde97b4 100644 --- a/include/Times.h +++ b/include/Times.h @@ -99,6 +99,7 @@ double diff_walltime(WallTimeSpec start, Bool ok_start); void SW_WT_StartTime(SW_WALLTIME *wt); void SW_WT_TimeRun(WallTimeSpec ts, Bool ok_ts, SW_WALLTIME *wt); void SW_WT_ReportTime(SW_WALLTIME wt, LOG_INFO* LogInfo); +void timeStringISO8601(char *timeString, int stringLength); #ifdef __cplusplus } diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index b5dd3a792..d4e47e6ff 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1374,7 +1374,6 @@ static void fill_netCDF_with_global_atts(SW_NETCDF* SW_netCDF, int* ncFileID, char sourceStr[40]; // 40 - valid size of the SOILWAT2 global `SW2_VERSION` + "SOILWAT2" char creationDateStr[21]; // 21 - valid size to hold a string of format YYYY-MM-DDTHH:MM:SSZ - time_t t = time(NULL); int attNum; const int numGlobAtts = (strcmp(domType, "s") == 0) ? 14 : 13; // Do or do not include "featureType" @@ -1401,7 +1400,7 @@ static void fill_netCDF_with_global_atts(SW_NETCDF* SW_netCDF, int* ncFileID, // Fill `sourceStr` and `creationDateStr` snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); - strftime(creationDateStr, sizeof creationDateStr, "%FT%TZ", gmtime(&t)); + timeStringISO8601(creationDateStr, sizeof creationDateStr); // Write out the necessary global attributes that are listed above for(attNum = 0; attNum < numGlobAtts; attNum++) { @@ -1428,7 +1427,6 @@ static void update_netCDF_global_atts(int* ncFileID, const char* domType, char sourceStr[40]; // 40 - valid size of the SOILWAT2 global `SW2_VERSION` + "SOILWAT2" char creationDateStr[21]; // 21 - valid size to hold a string of format YYYY-MM-DDTHH:MM:SSZ - time_t t = time(NULL); int attNum; const int numGlobAtts = (strcmp(domType, "s") == 0) ? 5 : 4; // Do or do not include "featureType" @@ -1450,7 +1448,7 @@ static void update_netCDF_global_atts(int* ncFileID, const char* domType, // Fill `sourceStr` and `creationDateStr` snprintf(sourceStr, 40, "SOILWAT2%s", SW2_VERSION); - strftime(creationDateStr, sizeof creationDateStr, "%FT%TZ", gmtime(&t)); + timeStringISO8601(creationDateStr, sizeof creationDateStr); // Write out the necessary global attributes that are listed above for(attNum = 0; attNum < numGlobAtts; attNum++) { diff --git a/src/Times.c b/src/Times.c index a3001b830..82a5b7b4e 100644 --- a/src/Times.c +++ b/src/Times.c @@ -404,3 +404,15 @@ void SW_WT_ReportTime(SW_WALLTIME wt, LOG_INFO* LogInfo) { ); } } + + +/** + @brief Current date and time in UTC formatted according to ISO 8601 + + @param[out] timeString Character array that returns the formatted time. + @param[in] stringLength Length of timeString (should be at least 21). +*/ +void timeStringISO8601(char *timeString, int stringLength) { + time_t t = time(NULL); + strftime(timeString, stringLength, "%FT%TZ", gmtime(&t)); +} From 147b19155cc14bcf2b6644ecc4ad3c3411684edc Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Tue, 9 Jan 2024 13:34:00 -0700 Subject: [PATCH 23/27] Address warnings/errors in tests compilation with `-DSWNETCDF` - These fixes include * Casting variables to Bool * Casting strings to/from a constant character * Not using the ternary operator trick of (cast){...} --- src/SW_netCDF.c | 43 +++++++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index d4e47e6ff..c05e24b22 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -428,7 +428,7 @@ static void get_single_byte_val(int ncFileID, int varID, size_t index[], * @param[out] dimVal String buffer to hold the resulting value * @param[out] LogInfo Holds information on warnings and errors */ -static void get_dim_val(int ncFileID, char* dimName, size_t* dimVal, +static void get_dim_val(int ncFileID, const char* dimName, size_t* dimVal, LOG_INFO* LogInfo) { int dimID = 0; @@ -452,8 +452,10 @@ static void get_dim_val(int ncFileID, char* dimName, size_t* dimVal, */ static Bool is_wgs84(char* crs_name) { const int numPosSyns = 5; - static char* wgs84_synonyms[] = {"WGS84", "WGS 84", "EPSG:4326", - "WGS_1984", "World Geodetic System 1984"}; + static char* wgs84_synonyms[] = { + (char *)"WGS84", (char *)"WGS 84", (char *)"EPSG:4326", + (char *)"WGS_1984", (char *)"World Geodetic System 1984" + }; for (int index = 0; index < numPosSyns; index++) { if (Str_CompareI(crs_name, wgs84_synonyms[index]) == 0) { @@ -657,10 +659,10 @@ static void fill_prog_netCDF_vals(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { unsigned long nDimY = SW_Domain->nDimY, nDimX = SW_Domain->nDimX; int progFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCprog]; int domFileID = SW_Domain->netCDFInfo.ncFileIDs[vNCdom]; - size_t* start = (strcmp(SW_Domain->DomainType, "s") == 0) ? - (size_t[1]){0} : (size_t[2]){0, 0}; - size_t* count = (strcmp(SW_Domain->DomainType, "s") == 0) ? - (size_t[1]){nSUIDs} : (size_t[2]){nDimY, nDimX}; + size_t start1D[] = {0}, start2D[] = {0, 0}; + size_t count1D[] = {nSUIDs}, count2D[] = {nDimY, nDimX}; + size_t* start = (strcmp(SW_Domain->DomainType, "s") == 0) ? start1D : start2D; + size_t* count = (strcmp(SW_Domain->DomainType, "s") == 0) ? count1D : count2D; signed char* vals = (signed char*)Mem_Malloc(nSUIDs * sizeof(signed char), "fill_prog_netCDF_vals()", @@ -1539,7 +1541,8 @@ static void create_full_var(int* ncFileID, int newVarType, const char* thirdDim = (siteDimExists) ? "site" : latName; const char* constDimNames[] = {thirdDim, lonName}; const char* timeVertNames[] = {"time", "vertical"}; - int timeVertVals[] = {timeSize, vertSize}, numTimeVertVals = 2; + unsigned long timeVertVals[] = {timeSize, vertSize}; + int numTimeVertVals = 2; for(index = 0; index < numTimeVertVals; index++) { if(timeVertVals[index] > 0) { @@ -1603,7 +1606,7 @@ void SW_NC_check(SW_DOMAIN* SW_Domain, int ncFileID, const char* fileName, const char *geoCRS = "crs_geogsc", *projCRS = "crs_projsc"; Bool geoCRSExists = varExists(ncFileID, geoCRS); Bool projCRSExists = varExists(ncFileID, projCRS); - char* impliedDomType = (dimExists("site", ncFileID)) ? "s" : "xy"; + const char* impliedDomType = (dimExists("site", ncFileID)) ? "s" : "xy"; Bool dimMismatch = swFALSE; size_t latDimVal = 0, lonDimVal = 0, SDimVal = 0; @@ -1649,10 +1652,9 @@ void SW_NC_check(SW_DOMAIN* SW_Domain, int ncFileID, const char* fileName, double projStdParallel[2]; // Compare to standard_parallel is projected CRS int attNum; - char* attFailMsg = "The attribute '%s' of the variable '%s' " - "within the file %s does not match the one " - "in the domain input file. Please make sure " - "these match."; + const char* attFailMsg = "The attribute '%s' of the variable '%s' " + "within the file %s does not match the one in the domain input " + "file. Please make sure these match."; /* Make sure the domain types are consistent @@ -1674,7 +1676,7 @@ void SW_NC_check(SW_DOMAIN* SW_Domain, int ncFileID, const char* fileName, return; // Exit function prematurely due to error } - dimMismatch = SDimVal != SW_Domain->nDimS; + dimMismatch = (Bool) (SDimVal != SW_Domain->nDimS); } else if(strcmp(impliedDomType, "xy") == 0) { if(geoIsPrimCRS && geoCRSExists) { get_dim_val(ncFileID, "lat", &latDimVal, LogInfo); @@ -1700,8 +1702,8 @@ void SW_NC_check(SW_DOMAIN* SW_Domain, int ncFileID, const char* fileName, return; // Exit function prematurely due to error } - dimMismatch = latDimVal != SW_Domain->nDimY || - lonDimVal != SW_Domain->nDimX; + dimMismatch = (Bool) (latDimVal != SW_Domain->nDimY || + lonDimVal != SW_Domain->nDimX); } if(dimMismatch) { @@ -1974,7 +1976,7 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { SW_NETCDF* SW_netCDF = &SW_Domain->netCDFInfo; Bool primCRSIsGeo = SW_Domain->netCDFInfo.primary_crs_is_geographic; - Bool domTypeIsS = strcmp(SW_Domain->DomainType, "s") == 0; + Bool domTypeIsS = (Bool) (strcmp(SW_Domain->DomainType, "s") == 0); const char* projGridMap = "crs_projsc: x y crs_geogsc: lat lon"; const char* geoGridMap = "crs_geogsc"; const char* sCoord = "lat lon site"; @@ -2001,7 +2003,7 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { Bool progFileIsDom = (Bool) (strcmp(progFileName, domFileName) == 0); Bool progFileExists = FileExists(progFileName); Bool progVarExists = varExists(*progFileID, progVarName); - Bool createOrModFile = !progFileExists || (progFileIsDom && !progVarExists); + Bool createOrModFile = (Bool) (!progFileExists || (progFileIsDom && !progVarExists)); /* If the progress file is not to be created or modified, check it @@ -2083,7 +2085,8 @@ void SW_NC_set_progress(Bool isFailure, const char* domType, int progFileID, LOG_INFO* LogInfo) { const signed char mark = (isFailure) ? PRGRSS_FAIL : PRGRSS_DONE; - size_t *count = (strcmp(domType, "s") == 0) ? (size_t[1]){1} : (size_t[2]){1, 1}; + size_t count1D[] = {1}, count2D[] = {1, 1}; + size_t *count = (strcmp(domType, "s") == 0) ? count1D : count2D; fill_netCDF_var_byte(progFileID, progVarID, &mark, ncSUID, count, LogInfo); nc_sync(progFileID); @@ -2124,7 +2127,7 @@ void SW_NC_read_inputs(SW_ALL* sw, SW_DOMAIN* SW_Domain, size_t ncSUID[], LOG_INFO* LogInfo) { int file, varNum; - Bool domTypeS = Str_CompareI(SW_Domain->DomainType, "s") == 0; + Bool domTypeS = (Bool) (Str_CompareI(SW_Domain->DomainType, (char *)"s") == 0); const int numInFilesNC = 1; const int numDomVals = 2; const int numVals[] = {numDomVals}; From 11c03fbadfc06648e7fc426f51cb3f30ea96e6c5 Mon Sep 17 00:00:00 2001 From: Nicholas Persley Date: Tue, 9 Jan 2024 13:34:19 -0700 Subject: [PATCH 24/27] Deep copy netCDF information in tests - Tests now pass when SWNETCDF is defined - New function `SW_NC_deepCopy()` * Deep copying all of the netCDF information from one SW_NETCDF instance to another * Called in `SW_DOM_deepCopy()` when tests are being run - Update the calls to `SW_F_init_ptrs()`/`SW_F_deconstruct()` to `SW_DOM_init_ptrs()`/`SW_DOM_deconstruct()` --- include/SW_netCDF.h | 1 + src/SW_Domain.c | 4 ++++ src/SW_netCDF.c | 44 ++++++++++++++++++++++++++++++++++ tests/gtests/sw_testhelpers.cc | 4 ++-- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/include/SW_netCDF.h b/include/SW_netCDF.h index 3337dc527..7253c2298 100644 --- a/include/SW_netCDF.h +++ b/include/SW_netCDF.h @@ -41,6 +41,7 @@ void SW_NC_init_ptrs(SW_NETCDF* SW_netCDF); void SW_NC_deconstruct(SW_NETCDF* SW_netCDF); void SW_NC_open_dom_prog_files(SW_NETCDF* SW_netCDF, LOG_INFO* LogInfo); void SW_NC_close_files(SW_NETCDF* SW_netCDF); +void SW_NC_deepCopy(SW_NETCDF* source, SW_NETCDF* dest, LOG_INFO* LogInfo); #ifdef __cplusplus } diff --git a/src/SW_Domain.c b/src/SW_Domain.c index f7fe8c59b..6d4711e91 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -338,6 +338,10 @@ void SW_DOM_deepCopy(SW_DOMAIN* source, SW_DOMAIN* dest, LOG_INFO* LogInfo) { memcpy(dest, source, sizeof (*dest)); SW_F_deepCopy(&dest->PathInfo, &source->PathInfo, LogInfo); + + #if defined(SWNETCDF) + SW_NC_deepCopy(&dest->netCDFInfo, &source->netCDFInfo, LogInfo); + #endif } void SW_DOM_init_ptrs(SW_DOMAIN* SW_Domain) { diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index c05e24b22..630f379e6 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -2384,3 +2384,47 @@ void SW_NC_close_files(SW_NETCDF* SW_netCDF) { nc_close(SW_netCDF->ncFileIDs[fileNum]); } } + +/** + * @brief Deep copy a source instance of SW_NETCDF into a destination instance + * + * @param[in] source Source struct of type SW_NETCDF to copy + * @param[out] dest Destination struct of type SW_NETCDF to be copied into + * @param[out] LogInfo Holds information on warnings and errors +*/ +void SW_NC_deepCopy(SW_NETCDF* source, SW_NETCDF* dest, LOG_INFO* LogInfo) { + int index, numIndivCopy = 5; + + char* srcStrs[] = { + source->title, source->author, source->institution, source->comment, + source->coordinate_system + }; + + char** destStrs[] = { + &dest->title, &dest->author, &dest->institution, &dest->comment, + &dest->coordinate_system + }; + + memcpy(dest, source, sizeof(*dest)); + + SW_NC_init_ptrs(dest); + + for(index = 0; index < numIndivCopy; index++) { + *destStrs[index] = Str_Dup(srcStrs[index], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to + } + } + + for(index = 0; index < SW_NVARNC; index++) { + dest->varNC[index] = Str_Dup(source->varNC[index], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + + dest->InFilesNC[index] = Str_Dup(source->InFilesNC[index], LogInfo); + if(LogInfo->stopRun) { + return; // Exit function prematurely due to error + } + } +} diff --git a/tests/gtests/sw_testhelpers.cc b/tests/gtests/sw_testhelpers.cc index 97548dc84..856a2b31f 100644 --- a/tests/gtests/sw_testhelpers.cc +++ b/tests/gtests/sw_testhelpers.cc @@ -144,7 +144,7 @@ void setup_testGlobalSoilwatTemplate() { // Initialize SOILWAT2 variables and read values from example input file sw_init_logs(NULL, &LogInfo); - SW_F_init_ptrs(template_SW_Domain.PathInfo.InFiles); + SW_DOM_init_ptrs(&template_SW_Domain); SW_CTL_init_ptrs(&template_SW_All); template_SW_Domain.PathInfo.InFiles[eFirst] = Str_Dup(DFLT_FIRSTFILE, &LogInfo); @@ -184,6 +184,6 @@ void setup_testGlobalSoilwatTemplate() { /* Free allocated memory of global test variables */ void teardown_testGlobalSoilwatTemplate() { - SW_F_deconstruct(template_SW_Domain.PathInfo.InFiles); + SW_DOM_deconstruct(&template_SW_Domain); SW_CTL_clear_model(swTRUE, &template_SW_All); } From 6bbdaf27530ab70157b4e26aa381e4798cd01a9f Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 9 Jan 2024 16:13:30 -0500 Subject: [PATCH 25/27] Simple progress messages on the console - new `sw_message()` - struct LOG_INFO gains new attribute "printProgressMsg" * progress messages are turned off by default via `sw_init_logs()`: this is the case for gtests, STEPWAT2, and rSOILWAT2 * SOILWAT2 main() turns on the printing of these progress messages unless user requests "quiet" mode --- include/SW_datastructs.h | 3 ++- include/filefuncs.h | 1 + src/SW_Control.c | 8 ++++++++ src/SW_Domain.c | 6 ++++++ src/SW_Main.c | 14 ++++++++++---- src/SW_Main_lib.c | 4 ++++ src/SW_Output_outtext.c | 6 ++++++ src/SW_netCDF.c | 11 +++++++++++ src/filefuncs.c | 18 ++++++++++++++++++ 9 files changed, 66 insertions(+), 5 deletions(-) diff --git a/include/SW_datastructs.h b/include/SW_datastructs.h index dec36a820..561fe6a93 100644 --- a/include/SW_datastructs.h +++ b/include/SW_datastructs.h @@ -769,7 +769,8 @@ typedef struct { Bool stopRun; // Specifies if an error has occurred and // the program needs to stop early (backtrack) - Bool QuietMode; /**< Don't print version, error message, or notify user about logfile (only used by SOILWAT2) */ + Bool QuietMode, /**< Don't print version, error message, or notify user about logfile (only used by SOILWAT2) */ + printProgressMsg; /**< Do/don't print progress messages to the console */ } LOG_INFO; typedef struct { diff --git a/include/filefuncs.h b/include/filefuncs.h index 29bf03663..c05c12a50 100644 --- a/include/filefuncs.h +++ b/include/filefuncs.h @@ -32,6 +32,7 @@ Bool MkDir(const char *dname, LOG_INFO* LogInfo); Bool RemoveFiles(const char *fspec, LOG_INFO* LogInfo); Bool CopyFile(const char *from, const char *to, LOG_INFO* LogInfo); void LogError(LOG_INFO* LogInfo, const int mode, const char *fmt, ...); +void sw_message(const char *msg); int key_to_id(const char* key, const char **possibleKeys, int numPossKeys); diff --git a/src/SW_Control.c b/src/SW_Control.c index 82a7440b4..ceca8b569 100644 --- a/src/SW_Control.c +++ b/src/SW_Control.c @@ -222,6 +222,12 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], set_walltime(&tss, &ok_tss); + #if defined(SOILWAT) + if(main_LogInfo->printProgressMsg) { + sw_message("is running simulations across the domain ..."); + } + #endif + /* Loop over suids in simulation set of domain */ for(suid = SW_Domain->startSimSet; suid < SW_Domain->endSimSet; suid++) { @@ -238,6 +244,8 @@ void SW_CTL_RunSimSet(SW_ALL *sw_template, SW_OUTPUT_POINTERS SW_OutputPtrs[], LOG_INFO local_LogInfo; sw_init_logs(main_LogInfo->logfp, &local_LogInfo); + local_LogInfo.printProgressMsg = main_LogInfo->printProgressMsg; + /* Check if suid needs to be simulated */ SW_DOM_calc_ncSuid(SW_Domain, suid, ncSuid); diff --git a/src/SW_Domain.c b/src/SW_Domain.c index 6d4711e91..c7fd1cdb3 100644 --- a/src/SW_Domain.c +++ b/src/SW_Domain.c @@ -320,6 +320,12 @@ void SW_DOM_SimSet(SW_DOMAIN* SW_Domain, unsigned long userSUID, *startSimSet = userSUID - 1; *endSimSet = userSUID; } else { + #if defined(SOILWAT) + if(LogInfo->printProgressMsg) { + sw_message("is identifying the simulation set ..."); + } + #endif + *endSimSet = SW_Domain->nSUIDs; for(*startSimSet = 0; *startSimSet < *endSimSet; (*startSimSet)++) { SW_DOM_calc_ncSuid(SW_Domain, *startSimSet, startSuid); diff --git a/src/SW_Main.c b/src/SW_Main.c index 078cca918..35fd2158a 100644 --- a/src/SW_Main.c +++ b/src/SW_Main.c @@ -80,10 +80,13 @@ int main(int argc, char **argv) { goto finishProgram; } - // Print version if not in quiet mode - if (!LogInfo.QuietMode) { - sw_print_version(); - } + // SOILWAT2: do print progress to console unless user requests quiet + LogInfo.printProgressMsg = (Bool)(!LogInfo.QuietMode); + + if (LogInfo.printProgressMsg) { + sw_message("started."); + sw_print_version(); + } // setup and construct domain SW_CTL_setup_domain(userSUID, &SW_Domain, &LogInfo); @@ -162,6 +165,9 @@ int main(int argc, char **argv) { SW_WT_ReportTime(SW_WallTime, &LogInfo); sw_wrapup_logs(&LogInfo); sw_fail_on_error(&LogInfo); + if (LogInfo.printProgressMsg) { + sw_message("ended."); + } } return 0; diff --git a/src/SW_Main_lib.c b/src/SW_Main_lib.c index cb0c3a70d..2522e2825 100644 --- a/src/SW_Main_lib.c +++ b/src/SW_Main_lib.c @@ -261,6 +261,9 @@ void sw_fail_on_error(LOG_INFO* LogInfo) { if(!LogInfo->QuietMode) { fprintf(stderr, "%s", LogInfo->errorMsg); } + if(LogInfo->printProgressMsg) { + sw_message("ended."); + } exit(EXIT_FAILURE); } #endif @@ -280,6 +283,7 @@ void sw_init_logs(FILE* logInitPtr, LOG_INFO* LogInfo) { LogInfo->stopRun = swFALSE; LogInfo->QuietMode = swFALSE; + LogInfo->printProgressMsg = swFALSE; LogInfo->numWarnings = 0; LogInfo->numDomainWarnings = 0; LogInfo->numDomainErrors = 0; diff --git a/src/SW_Output_outtext.c b/src/SW_Output_outtext.c index ea73b2dec..cdabf9d27 100644 --- a/src/SW_Output_outtext.c +++ b/src/SW_Output_outtext.c @@ -335,6 +335,12 @@ void SW_OUT_create_files(SW_FILE_STATUS* SW_FileStatus, SW_OUTPUT* SW_Output, OutPeriod pd; + #if defined(SOILWAT) + if(LogInfo->printProgressMsg) { + sw_message("is creating output files ..."); + } + #endif + ForEachOutPeriod(pd) { if (GenOutput->use_OutPeriod[pd]) { _create_csv_files(SW_FileStatus, pd, InFiles, LogInfo); diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 630f379e6..0a426bd09 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -1853,6 +1853,12 @@ void SW_NC_create_domain_template(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { return; // Exit prematurely due to error } + #if defined(SOILWAT) + if(LogInfo->printProgressMsg) { + sw_message("is creating a domain template ..."); + } + #endif + if(nc_create(DOMAIN_TEMP, NC_NETCDF4, domFileID) != NC_NOERR) { LogError(LogInfo, LOGERROR, "Could not create new domain template due " "to something internal."); @@ -2024,6 +2030,11 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { create_full_var(progFileID, NC_BYTE, 0, 0, progVarName, attNames, attVals, numAtts, LogInfo); } else { + #if defined(SOILWAT) + if(LogInfo->printProgressMsg) { + sw_message("is creating a progress tracker ..."); + } + #endif SW_NC_create_template(domFileName, domFileID, progFileName, progFileID, NC_BYTE, 0, 0, progVarName, attNames, attVals, numAtts, swFALSE, freq, LogInfo); diff --git a/src/filefuncs.c b/src/filefuncs.c index 884f0a92b..ff77ba65f 100644 --- a/src/filefuncs.c +++ b/src/filefuncs.c @@ -15,6 +15,7 @@ #include "include/filefuncs.h" #include "include/myMemory.h" +#include "include/Times.h" /* 01/05/2011 (drs) removed unused variable *p from MkDir() @@ -207,6 +208,23 @@ void LogError(LOG_INFO* LogInfo, const int mode, const char *fmt, ...) { } + + +/** + @brief Print a SOILWAT2 status message + + @param[in] msg Message string. +*/ +void sw_message(const char *msg) { + char timeString[21]; + timeStringISO8601(timeString, sizeof timeString); + + swprintf("SOILWAT2 (%s) %s\n", timeString, msg); +} + + + + /**************************************************************/ Bool GetALine(FILE *f, char buf[], int numChars) { /* Read a line of possibly commented input from the file *f. From d75e5d13fd4a46384947a2f75e9836fd8adc9439 Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 9 Jan 2024 16:27:39 -0500 Subject: [PATCH 26/27] Fix SW_WT_ReportTime() - now reports 0 wall time -- only negative wall time values indicate failure --- src/Times.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Times.c b/src/Times.c index 82a5b7b4e..52c936963 100644 --- a/src/Times.c +++ b/src/Times.c @@ -364,7 +364,7 @@ void SW_WT_ReportTime(SW_WALLTIME wt, LOG_INFO* LogInfo) { total_time = diff_walltime(wt.timeStart, wt.has_walltime); // negative if failed - if (GT(total_time, 0.)) { + if (GE(total_time, 0.)) { fprintf(logfp, " * Total wall time: %.2f [seconds]\n", total_time); } else { fprintf(logfp, " * Wall time failed.\n"); From 84dbffcb2b4eac0968564b3f645350ad6fb1231b Mon Sep 17 00:00:00 2001 From: Daniel Schlaepfer Date: Tue, 9 Jan 2024 19:28:45 -0500 Subject: [PATCH 27/27] Fix progress message of creating a progress tracker - the message should be displayed independent of where the progress tracker variable is located (domain.nc or progress.nc) --- src/SW_netCDF.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/SW_netCDF.c b/src/SW_netCDF.c index 0a426bd09..e6b3a9e4c 100644 --- a/src/SW_netCDF.c +++ b/src/SW_netCDF.c @@ -2024,17 +2024,18 @@ void SW_NC_create_progress(SW_DOMAIN* SW_Domain, LOG_INFO* LogInfo) { SW_NC_check(SW_Domain, *progFileID, progFileName, LogInfo); } else { + #if defined(SOILWAT) + if(LogInfo->printProgressMsg) { + sw_message("is creating a progress tracker ..."); + } + #endif + if(progFileExists) { nc_redef(*progFileID); create_full_var(progFileID, NC_BYTE, 0, 0, progVarName, attNames, attVals, numAtts, LogInfo); } else { - #if defined(SOILWAT) - if(LogInfo->printProgressMsg) { - sw_message("is creating a progress tracker ..."); - } - #endif SW_NC_create_template(domFileName, domFileID, progFileName, progFileID, NC_BYTE, 0, 0, progVarName, attNames, attVals, numAtts, swFALSE, freq, LogInfo);