diff --git a/cmake-config b/cmake-config index 8575bf104e..3797a85321 100755 --- a/cmake-config +++ b/cmake-config @@ -541,6 +541,7 @@ ${FAODEL_SYMBOLS} \ -D ParMETIS_ROOT:PATH=${PARMETIS_PATH} \ -D PNetCDF_ROOT:PATH=${PNETCDF_PATH} \ -D fmt_ROOT:PATH=${FMT_PATH} \ +-D CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=ON \ $EXTRA_ARGS \ ${ACCESS} diff --git a/packages/seacas/libraries/ioss/src/CMakeLists.txt b/packages/seacas/libraries/ioss/src/CMakeLists.txt index 757e1079a1..51a005fb4a 100644 --- a/packages/seacas/libraries/ioss/src/CMakeLists.txt +++ b/packages/seacas/libraries/ioss/src/CMakeLists.txt @@ -150,4 +150,7 @@ TRIBITS_ADD_TEST_DIRECTORIES(utest) IF (TPL_ENABLE_GTest) TRIBITS_ADD_TEST_DIRECTORIES(unit_tests) + IF (TPL_ENABLE_Catalyst2) + TRIBITS_ADD_TEST_DIRECTORIES(catalyst_tests) + ENDIF() ENDIF() diff --git a/packages/seacas/libraries/ioss/src/catalyst/CMakeLists.txt b/packages/seacas/libraries/ioss/src/catalyst/CMakeLists.txt index 7ee0946b90..614b674012 100644 --- a/packages/seacas/libraries/ioss/src/catalyst/CMakeLists.txt +++ b/packages/seacas/libraries/ioss/src/catalyst/CMakeLists.txt @@ -17,16 +17,10 @@ TRIBITS_ADD_LIBRARY( Iocatalyst HEADERS ${HEADERS} SOURCES ${SOURCES} - DEPLIBS Ioss ${DEPLIBS} + DEPLIBS Ioss ) generate_export_header(Iocatalyst) target_include_directories(Iocatalyst PUBLIC "$") - -#IF (BUILD_TESTING) -# ENABLE_TESTING() -#ENDIF (BUILD_TESTING) -# -#TRIBITS_ADD_TEST_DIRECTORIES(utest) diff --git a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystLogging.C b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystLogging.C new file mode 100644 index 0000000000..a426ffe4c8 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystLogging.C @@ -0,0 +1,201 @@ +// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include +#include +#include +#include +#include + +namespace Iocatalyst { + + CatalystLogging::CatalystLogging() { initializeDefaults(); } + + void CatalystLogging::initializeDefaults() + { + catalystLoggingEnabled = false; + logFileName = getDefaultLogFileName(); + logOutputDirectoryPath = getDefaultLogOutputDirectoryPath(); + properties = nullptr; + } + + void CatalystLogging::setProperties(const Ioss::PropertyManager *my_properties) + { + initializeDefaults(); + this->properties = my_properties; + if (this->properties) { + if (this->properties->exists(enabledProp)) { + catalystLoggingEnabled = this->properties->get(enabledProp).get_int(); + } + if (this->properties->exists(fileNameProp)) { + logFileName = this->properties->get(fileNameProp).get_string(); + } + if (this->properties->exists(directoryPathProp)) { + logOutputDirectoryPath = this->properties->get(directoryPathProp).get_string(); + } + } + } + + std::vector CatalystLogging::writeToLogFile() + { + std::vector logLine; + if (properties) { + std::fstream logFile; + logFile.open(getLogFilePath(), std::ios::out | std::ios::app); + if (!logFile) { + std::ostringstream errmsg; + errmsg << "Unable to open Catalyst log file: " << getLogFilePath() << "\n"; + IOSS_ERROR(errmsg); + } + else { + std::vector headers = getLogFileHeaders(); + if (isLogFileEmpty()) { + writeVectorWithDelimeter(logFile, headers, getDelimeter()); + } + logLine = getLogOutputFromProps(headers); + writeVectorWithDelimeter(logFile, logLine, getDelimeter()); + logFile.close(); + } + } + return logLine; + } + + std::vector CatalystLogging::getLogFileHeaders() + { + std::vector headers; + if (properties) { + Ioss::NameList names = properties->describe(); + for (auto &name : names) { + if (isCatalystLoggingProp(name)) { + if (isSupportedPropType(name) && !isReservedPropName(name)) { + headers.push_back(getHeaderNameFromPropName(name)); + } + } + } + } + std::sort(headers.begin(), headers.end()); + return headers; + } + + bool CatalystLogging::isLogFileEmpty() + { + std::ifstream logFile; + logFile.open(getLogFilePath()); + bool result = logFile.peek() == std::ifstream::traits_type::eof(); + logFile.close(); + return result; + } + + void CatalystLogging::writeVectorWithDelimeter(std::fstream &file, + const std::vector &string_vector, + char delimeter) + { + if (string_vector.empty()) { + return; + } + for (size_t i = 0; i < string_vector.size(); i++) { + file << string_vector[i]; + if (i < string_vector.size() - 1) { + file << delimeter; + } + } + file << "\n"; + } + + std::vector> CatalystLogging::readLogFile() + { + return readLogFile(getLogFilePath()); + } + + std::vector> CatalystLogging::readLogFile(const std::string &logFilePath) + { + std::vector> result; + std::fstream logFile; + logFile.open(logFilePath); + if (logFile) { + std::string line; + while (getline(logFile, line)) { + result.push_back( + CatalystLogging::splitStringWithDelimeter(line, CatalystLogging::getDelimeter())); + } + logFile.close(); + } + return result; + } + + std::vector CatalystLogging::splitStringWithDelimeter(const std::string &input, + char delimeter) + { + std::string buffer = ""; + std::vector result; + enum ParseState { UNQUOTED, QUOTED, QUOTEDQUOTE }; + ParseState state = UNQUOTED; + for (size_t i = 0; i < input.size(); i++) { + switch (state) { + case UNQUOTED: + if (input[i] == delimeter) { + result.push_back(buffer); + buffer.clear(); + } + else if (input[i] == '"') { + state = QUOTED; + buffer += "\""; + } + else { + buffer += input[i]; + } + break; + case QUOTED: + if (input[i] == '"') { + state = UNQUOTED; + buffer += "\""; + } + else { + buffer += input[i]; + } + break; + case QUOTEDQUOTE: + if (input[i] == delimeter) { + state = UNQUOTED; + result.push_back(buffer); + buffer.clear(); + } + else if (input[i] == '"') { + state = QUOTED; + buffer += "\""; + } + else { + state = UNQUOTED; + buffer += input[i]; + } + break; + } + } + if (!buffer.empty()) { + result.push_back(buffer); + } + return result; + } + + std::vector CatalystLogging::getLogOutputFromProps(std::vector &headers) + { + std::vector logOutput; + if (properties) { + for (auto &header : headers) { + std::string propName = getPropNameFromHeaderName(header); + Ioss::Property prop = properties->get(propName); + switch (prop.get_type()) { + case Ioss::Property::REAL: logOutput.push_back(std::to_string(prop.get_real())); break; + case Ioss::Property::INTEGER: logOutput.push_back(std::to_string(prop.get_int())); break; + case Ioss::Property::STRING: logOutput.push_back(prop.get_string()); break; + default: logOutput.push_back("Unsupported property type for " + propName); + } + } + } + return logOutput; + } + +} // namespace Iocatalyst diff --git a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystLogging.h b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystLogging.h new file mode 100644 index 0000000000..84c5af3445 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystLogging.h @@ -0,0 +1,144 @@ +// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#ifndef IOSS_IOVS_CATALYST_LOGGING_H +#define IOSS_IOVS_CATALYST_LOGGING_H + +#include "iocatalyst_export.h" + +#include +#include +#include +#include + +namespace Iocatalyst { + + class IOCATALYST_EXPORT CatalystLogging + { + // Enables Catalyst log output from IOSS when Catalyst CGNS or + // Exodus IOSS databases are created. Rank 0 of the application + // writes an entry to a CSV (comma separted value) log file upon + // IOSS database creation. Log output is controlled through + // IOSS properties. IOSS properties that control logging must be + // prepened with the string "CATALYST_LOGGING_". + // + // There are three reserved IOSS property names for logging. + // + // "CATALYST_LOGGING_ENABLED" : enables Catalyst log output when passed + // an argument of "true or a non-zero integer". Default is "false". + // + // "CATALYST_LOGGING_FILE_NAME" : string specifying the log file output + // name. Default is "catalyst_log.csv". + // + // "CATALYST_LOGGING_OUTPUT_DIRECTORY_PATH" : string specifying an absolute + // or relative path to the log file. Default is current working directory, "". + // + // Real, Integer, and String IOSS properties prepended by the string + // "CATALYST_LOGGING_" are used to specify output for the log line in the CSV + // output log file. The logger will remove the prepended string and create + // a header line in the CSV file sorted by name. + // + // Example application code creating a Catalyst IOSS database with logging: + // + // Ioss::PropertyManager *p; + // p->add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + // p->add(Ioss::Property("CATALYST_LOGGING_FILE_NAME", "app_log.csv")); + // p->add(Ioss::Property("CATALYST_LOGGING_OUTPUT_DIRECTORY_PATH, "/etc/logs/")); + // p->add(Ioss::Property("CATALYST_LOGGING_NUM_RANKS", getNumRanks())); + // p->add(Ioss::Property("CATALYST_LOGGING_DATE", getDate())); + // p->add(Ioss::Property("CATALYST_LOGGING_USER", getUser())); + // p->add(Ioss::Property("CATALYST_LOGGING_APP_NAME", getAppName())); + // + // The IOSS properties contained in *p are passed to the IOSS + // Ioss::IOFactory::create(). A log entry will be appended to the log file + // at "/etc/logs/app_log_.csv" every time a Catalyst database is created by + // a running instance of the application. The CSV log file will have the following + // format, which can be easily read by Python. + // + // APP_NAME,DATE,NUM_RANKS,USER + // goo,November 10th,16,joe + // bar,December 12th,8,stan + // + // If an IOSS string property contains commas, these need to be quoted. + // + // p->add(Ioss::Property("CATALYST_LOGGING_ADDRESS", "\"123 main, PO 4, ND, 34422\"")) + // + // Quotes inside strings must also be quoted. + // + // p->add(Ioss::Property("CATALYST_LOGGING_QUOTE", "I am \"\"Dave\"\"")) + + public: + CatalystLogging(); + + bool isCatalystLoggingON() { return catalystLoggingEnabled; }; + std::string getLogFileName() { return logFileName; }; + static std::string getDefaultLogFileName() { return "catalyst_log.csv"; }; + std::string getLogOutputDirectoryPath() { return logOutputDirectoryPath; }; + std::string getDefaultLogOutputDirectoryPath() { return ""; }; + void setProperties(const Ioss::PropertyManager *properties); + std::vector getLogFileHeaders(); + std::vector writeToLogFile(); + std::vector> readLogFile(); + static std::vector> readLogFile(const std::string &logFilePath); + std::string getLogFilePath() + { + if (logOutputDirectoryPath.empty()) { + return getLogFileName(); + } + else { + std::string opath = getLogOutputDirectoryPath(); + if (opath.back() != '/') { + opath += '/'; + } + return opath + getLogFileName(); + } + }; + static char getDelimeter() { return ','; }; + bool isCatalystLoggingProp(std::string &propName) { return propName.rfind(logPrefix, 0) == 0; }; + std::string getHeaderNameFromPropName(std::string &propName) + { + return propName.substr(logPrefix.length()); + }; + std::string getPropNameFromHeaderName(std::string &headerName) + { + return logPrefix + headerName; + }; + bool isReservedPropName(std::string &propName) + { + return propName == enabledProp || propName == fileNameProp || propName == directoryPathProp; + }; + bool isSupportedPropType(std::string &propName) + { + bool retVal = false; + if (properties && properties->exists(propName)) { + Ioss::Property::BasicType type = properties->get(propName).get_type(); + retVal = (type == Ioss::Property::INTEGER || type == Ioss::Property::REAL || + type == Ioss::Property::STRING); + } + return retVal; + }; + + private: + bool catalystLoggingEnabled; + std::string logFileName; + std::string logOutputDirectoryPath; + const Ioss::PropertyManager *properties; + std::string logPrefix = "CATALYST_LOGGING_"; + std::string enabledProp = logPrefix + "ENABLED"; + std::string fileNameProp = logPrefix + "FILE_NAME"; + std::string directoryPathProp = logPrefix + "OUTPUT_DIRECTORY_PATH"; + void initializeDefaults(); + void writeVectorWithDelimeter(std::fstream &file, const std::vector &string_vector, + char delimeter); + static std::vector splitStringWithDelimeter(const std::string &input, + char delimeter); + bool isLogFileEmpty(); + std::vector getLogOutputFromProps(std::vector &headers); + }; + +} // namespace Iocatalyst + +#endif diff --git a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystManager.C b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystManager.C new file mode 100644 index 0000000000..aa78b1c9ee --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystManager.C @@ -0,0 +1,323 @@ +// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include +#include +#include + +namespace Iocatalyst { + + CatalystManager::CatalystManager() { reset(); } + + CatalystManager::~CatalystManager() {} + + void CatalystManager::writeToCatalystLogFile(const Ioss::ParallelUtils &putils, + const Ioss::PropertyManager &props) + { + if (putils.parallel_rank() == 0) { + CatalystLogging catLog = CatalystLogging(); + catLog.setProperties(&props); + if (catLog.isCatalystLoggingON()) { + catLog.writeToLogFile(); + } + } + putils.barrier(); + } + + std::string CatalystManager::getCatDataPath(const Ioss::PropertyManager &props) + { + auto inputName = CATALYST_INPUT_DEFAULT; + if (props.exists(CATALYST_INPUT_NAME)) { + inputName = props.get(CATALYST_INPUT_NAME).get_string(); + } + return CATALYST + FS + CHANNELS + FS + inputName + FS + DATA; + } + + CatalystManager::CatalystPipelineID + CatalystManager::initialize(const Ioss::PropertyManager &props, const Ioss::ParallelUtils &putils) + { + if (getManagerState() != mInit) { + std::ostringstream errmsg; + errmsg << "Catalyst Manager not in mInit state"; + IOSS_ERROR(errmsg); + } + + CatalystManager::CatalystProps catalystProps; + catalystProps.catalystPipelineID = catalystOutputIDNumber; + incrementOutputCounts(); + + if (props.exists(CATALYST_BLOCK_PARSE_JSON_STRING)) { + catalystProps.catalystBlockJSON = props.get(CATALYST_BLOCK_PARSE_JSON_STRING).get_string(); + } + else if (props.exists(PHACTORI_JSON_SCRIPT)) { + bool readOkay = false; + std::string phactoriJSONFilePath = props.get(PHACTORI_JSON_SCRIPT).get_string(); + if (putils.parallel_rank() == 0) { + std::ifstream f(phactoriJSONFilePath); + if (f) { + std::ostringstream ss; + ss << f.rdbuf(); + catalystProps.catalystBlockJSON = ss.str(); + readOkay = true; + } + } + this->broadCastStatusCode(readOkay, putils); + if (!readOkay) { + std::ostringstream errmsg; + errmsg << "Unable to read input file: " << phactoriJSONFilePath << "\n"; + IOSS_ERROR(errmsg); + } + else { + this->broadCastString(catalystProps.catalystBlockJSON, putils); + } + } + + if (props.exists(CATALYST_SCRIPT)) { + catalystProps.catalystPythonFilename = props.get(CATALYST_SCRIPT).get_string(); + } + else { + catalystProps.catalystPythonFilename = this->getCatalystPythonDriverPath(); + } + + if (props.exists(CATALYST_SCRIPT_EXTRA_FILE)) { + catalystProps.catalystScriptExtraFile = props.get(CATALYST_SCRIPT_EXTRA_FILE).get_string(); + } + + if (props.exists(CATALYST_BLOCK_PARSE_INPUT_DECK_NAME)) { + catalystProps.catalystInputDeckName = + props.get(CATALYST_BLOCK_PARSE_INPUT_DECK_NAME).get_string(); + } + + if (props.exists(CATALYST_ENABLE_LOGGING)) { + catalystProps.enableLogging = props.get(CATALYST_ENABLE_LOGGING).get_int(); + } + + if (props.exists(CATALYST_DEBUG_LEVEL)) { + catalystProps.debugLevel = props.get(CATALYST_DEBUG_LEVEL).get_int(); + } + + if (props.exists(CATALYST_OUTPUT_DIRECTORY)) { + catalystProps.catalystOutputDirectory = props.get(CATALYST_OUTPUT_DIRECTORY).get_string(); + } + + if (props.exists(CATALYST_INPUT_NAME)) { + catalystProps.catalystInputName = props.get(CATALYST_INPUT_NAME).get_string(); + } + + if (props.exists(CATALYST_MULTI_INPUT_PIPELINE_NAME)) { + catalystProps.enableCatalystMultiInputPipeline = true; + catalystProps.catalystMultiInputPipelineName = + props.get(CATALYST_MULTI_INPUT_PIPELINE_NAME).get_string(); + } + + catPipes[catalystProps.catalystPipelineID] = catalystProps; + return catalystProps.catalystPipelineID; + } + + CatalystManager::CatalystProps &CatalystManager::getCatalystProps(CatalystPipelineID id) + { + if (catPipes.find(id) == catPipes.end()) { + std::ostringstream errmsg; + errmsg << "Catalyst Pipeline ID does not exist: " << id << "\n"; + IOSS_ERROR(errmsg); + } + return catPipes[id]; + } + + void CatalystManager::execute(CatalystManager::CatalystPipelineID id, int state, double time, + conduit_cpp::Node &data) + { + if (getManagerState() == mFinalize) { + std::ostringstream errmsg; + errmsg << "Catalyst Manager in mFinalize state, cannot execute()"; + IOSS_ERROR(errmsg); + } + auto p = getCatalystProps(id); + if (p.pipelineState != pExecute) { + std::ostringstream errmsg; + errmsg << "Database not in pExecute state, cannot execute()"; + IOSS_ERROR(errmsg); + } + if (getManagerState() == mInit) { + auto n = getInitializeConduit(); + catalyst_initialize(conduit_cpp::c_node(&n)); + managerState = mExecute; + } + + conduit_cpp::Node n; + addExecuteProps(n, p, state, time); + + if (p.enableCatalystMultiInputPipeline) { + setMultiInputWaitState(p.catalystPipelineID, state, time, data); + if (canExecuteMultiInputScript(p.catalystPipelineID)) { + for (auto p : catPipes) { + addExecuteData(n, p.second.catalystInputName, p.second.state, p.second.time, + p.second.data); + } + } + else { + return; + } + } + else { + addExecuteData(n, p.catalystInputName, state, time, data); + } + + catalyst_execute(conduit_cpp::c_node(&n)); + + if (p.enableCatalystMultiInputPipeline) { + if (canExecuteMultiInputScript(p.catalystPipelineID)) { + clearAllMultiInputWaitStates(p.catalystPipelineID); + } + } + } + + void CatalystManager::finalize(CatalystPipelineID id) + { + getCatalystProps(id).pipelineState = pFinalize; + managerState = mExecute; + bool canFinalizeManager = true; + for (auto p : catPipes) { + canFinalizeManager &= p.second.pipelineState == pFinalize; + } + if (canFinalizeManager) { + managerState = mFinalize; + conduit_cpp::Node node; + catalyst_finalize(conduit_cpp::c_node(&node)); + } + } + + CatalystManager::pState CatalystManager::getPipelineState(CatalystPipelineID id) + { + return getCatalystProps(id).pipelineState; + } + + conduit_cpp::Node CatalystManager::getInitializeConduit() + { + conduit_cpp::Node n; + for (auto p : catPipes) { + addScriptProps(n, p.second); + } + return n; + } + + void CatalystManager::addScriptProps(conduit_cpp::Node &n, const CatalystProps &p) + { + n[getCatScriptFnamePath(p)] = p.catalystPythonFilename; + n[getCatScriptArgsPath(p)].append().set(p.catalystInputName); + n[getCatScriptArgsPath(p)].append().set(p.catalystBlockJSON); + n[getCatScriptArgsPath(p)].append().set(p.catalystScriptExtraFile); + n[getCatScriptArgsPath(p)].append().set(p.catalystInputDeckName); + n[getCatScriptArgsPath(p)].append().set(p.catalystOutputDirectory); + n[getCatScriptArgsPath(p)].append().set(std::to_string(p.enableLogging)); + n[getCatScriptArgsPath(p)].append().set(std::to_string(p.debugLevel)); + } + + void CatalystManager::addExecuteProps(conduit_cpp::Node &n, const CatalystProps &p, int state, + double time) + { + n[getCatStatePath() + TIMESTEP].set(state - 1); + n[getCatStatePath() + CYCLE].set(state - 1); + n[getCatStatePath() + TIME].set(time); + auto scriptName = std::to_string(p.catalystPipelineID); + n[getCatStatePath() + PIPELINES + FS + scriptName] = scriptName; + } + + void CatalystManager::addExecuteData(conduit_cpp::Node &n, const std::string &channelName, + int state, double time, conduit_cpp::Node &data) + { + auto ipath = getCatChannelsPath() + channelName + FS; + n[ipath + TYPE].set(std::string(IOSS)); + auto dpath = ipath + FS + DATA; + n[dpath].set_external(data); + n[dpath + FS + TIMESTEP].set(state - 1); + n[dpath + FS + CYCLE].set(state - 1); + n[dpath + FS + TIME].set(time); + } + + void CatalystManager::setMultiInputWaitState(CatalystPipelineID id, int state, double time, + conduit_cpp::Node &data) + { + auto &p = CatalystManager::getInstance().getCatalystProps(id); + if (!p.enableCatalystMultiInputPipeline) { + std::ostringstream errmsg; + errmsg << "Catalyst pipeline is not a multi-input pipeline"; + IOSS_ERROR(errmsg); + } + p.pipelineState = pWaitExecute; + p.data.set_external(data); + p.state = state; + p.time = time; + } + + bool CatalystManager::canExecuteMultiInputScript(CatalystPipelineID id) + { + bool canExecute = true; + auto &p = CatalystManager::getInstance().getCatalystProps(id); + if (!p.enableCatalystMultiInputPipeline) { + std::ostringstream errmsg; + errmsg << "Catalyst pipeline is not a multi-input pipeline"; + IOSS_ERROR(errmsg); + } + auto name = p.catalystMultiInputPipelineName; + for (auto cp : catPipes) { + if (cp.second.enableCatalystMultiInputPipeline && + cp.second.catalystMultiInputPipelineName == name) { + canExecute &= cp.second.pipelineState == pWaitExecute; + } + } + return canExecute; + } + + void CatalystManager::clearAllMultiInputWaitStates(CatalystPipelineID id) + { + auto &p = CatalystManager::getInstance().getCatalystProps(id); + if (!p.enableCatalystMultiInputPipeline) { + std::ostringstream errmsg; + errmsg << "Catalyst pipeline is not a multi-input pipeline"; + IOSS_ERROR(errmsg); + } + auto name = p.catalystMultiInputPipelineName; + for (auto &cp : catPipes) { + if (cp.second.enableCatalystMultiInputPipeline && + cp.second.catalystMultiInputPipelineName == name) { + cp.second.pipelineState = pExecute; + cp.second.data.set(conduit_cpp::Node()); + } + } + } + + void CatalystManager::incrementOutputCounts() { catalystOutputIDNumber++; } + + void CatalystManager::broadCastString(IOSS_MAYBE_UNUSED std::string &s, + IOSS_MAYBE_UNUSED const Ioss::ParallelUtils &putils) + { + IOSS_PAR_UNUSED(s); + IOSS_PAR_UNUSED(dbinfo); +#ifdef SEACAS_HAVE_MPI + int size = s.size(); + putils.broadcast(size); + if (putils.parallel_rank() != 0) { + s.resize(size); + } + putils.broadcast(s); +#endif + } + + void CatalystManager::broadCastStatusCode(IOSS_MAYBE_UNUSED bool &statusCode, + IOSS_MAYBE_UNUSED const Ioss::ParallelUtils &putils) + { + IOSS_PAR_UNUSED(statusCode); + IOSS_PAR_UNUSED(dbinfo); +#ifdef SEACAS_HAVE_MPI + + int code = statusCode; + putils.broadcast(code); + statusCode = code; +#endif + } + +} // namespace Iocatalyst \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystManager.h b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystManager.h new file mode 100644 index 0000000000..a322097436 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_CatalystManager.h @@ -0,0 +1,158 @@ +// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#ifndef IOSS_IOVS_CATALYST_MANAGER_H +#define IOSS_IOVS_CATALYST_MANAGER_H + +#include "iocatalyst_export.h" +#include +#include + +namespace Iocatalyst { + + class IOCATALYST_EXPORT CatalystManager + { + public: + using CatalystPipelineID = unsigned int; + + enum mState { mInit, mExecute, mFinalize }; + enum pState { pWaitExecute, pExecute, pFinalize }; + + inline static const std::string ARGS = "args"; + inline static const std::string CATALYST = "catalyst"; + inline static const std::string CATALYST_BLOCK_PARSE_INPUT_DECK_NAME = + "CATALYST_BLOCK_PARSE_INPUT_DECK_NAME"; + inline static const std::string CATALYST_BLOCK_PARSE_JSON_STRING = + "CATALYST_BLOCK_PARSE_JSON_STRING"; + inline static const std::string CATALYST_DEBUG_LEVEL = "CATALYST_DEBUG_LEVEL"; + inline static const std::string CATALYST_ENABLE_LOGGING = "CATALYST_ENABLE_LOGGING"; + inline static const std::string CATALYST_OUTPUT_DIRECTORY = "CATALYST_OUTPUT_DIRECTORY"; + inline static const std::string CATALYST_OUTPUT_DEFAULT = "CatalystOutput"; + inline static const std::string CATALYST_INPUT_NAME = "CATALYST_INPUT_NAME"; + inline static const std::string CATALYST_INPUT_DEFAULT = "input"; + inline static const std::string CATALYST_MULTI_INPUT_PIPELINE_NAME = + "CATALYST_MULTI_INPUT_PIPELINE_NAME"; + inline static const std::string CATALYST_SCRIPT = "CATALYST_SCRIPT"; + inline static const std::string CATALYST_SCRIPT_EXTRA_FILE = "CATALYST_SCRIPT_EXTRA_FILE"; + inline static const std::string CHANNELS = "channels"; + inline static const std::string CYCLE = "cycle"; + inline static const std::string DATA = "data"; + inline static const std::string PHACTORI_JSON_SCRIPT = "PHACTORI_JSON_SCRIPT"; + inline static const std::string PIPELINES = "pipelines"; + inline static const std::string FILENAME = "filename"; + inline static const std::string FS = "/"; + inline static const std::string IOSS = "ioss"; + inline static const std::string SCRIPTS = "scripts"; + inline static const std::string STATE = "state"; + inline static const std::string TIME = "time"; + inline static const std::string TIMESTEP = "timestep"; + inline static const std::string TYPE = "type"; + + static CatalystManager &getInstance() + { + static CatalystManager instance; + return instance; + } + + std::string getCatalystPythonDriverPath() { return "/todo/create/real/path"; } + + conduit_cpp::Node getInitializeConduit(); + + mState getManagerState() { return managerState; } + + pState getPipelineState(CatalystPipelineID id); + + void writeToCatalystLogFile(const Ioss::ParallelUtils &putils, + const Ioss::PropertyManager &props); + + struct CatalystProps + { + CatalystProps() + { + catalystPipelineID = 0; + enableLogging = false; + debugLevel = 0; + catalystOutputDirectory = CATALYST_OUTPUT_DEFAULT; + catalystInputName = CATALYST_INPUT_DEFAULT; + enableCatalystMultiInputPipeline = false; + pipelineState = pExecute; + state = 0; + time = 0.0; + } + + CatalystPipelineID catalystPipelineID; + pState pipelineState; + bool enableCatalystMultiInputPipeline; + std::string catalystMultiInputPipelineName; + std::string catalystPythonFilename; + conduit_cpp::Node data; + int state; + double time; + + std::string catalystInputName; + std::string catalystBlockJSON; + std::string catalystScriptExtraFile; + std::string catalystInputDeckName; + std::string catalystOutputDirectory; + bool enableLogging; + int debugLevel; + }; + + CatalystPipelineID initialize(const Ioss::PropertyManager &props, + const Ioss::ParallelUtils &putils); + void execute(CatalystPipelineID id, int state, double time, conduit_cpp::Node &data); + void finalize(CatalystPipelineID id); + void addScriptProps(conduit_cpp::Node &n, const CatalystProps &p); + void addExecuteProps(conduit_cpp::Node &n, const CatalystProps &p, int state, double time); + void addExecuteData(conduit_cpp::Node &n, const std::string &channelName, int state, + double time, conduit_cpp::Node &data); + CatalystProps &getCatalystProps(CatalystPipelineID id); + std::string getCatDataPath(const Ioss::PropertyManager &props); + void setMultiInputWaitState(CatalystPipelineID id, int state, double time, + conduit_cpp::Node &data); + bool canExecuteMultiInputScript(CatalystPipelineID id); + void clearAllMultiInputWaitStates(CatalystPipelineID id); + void reset() + { + catalystOutputIDNumber = 0; + catPipes.clear(); + managerState = mInit; + } + + std::string getCatScriptFnamePath(const CatalystProps &p) + { + return getCatScriptPath(p) + FILENAME; + } + + std::string getCatScriptArgsPath(const CatalystProps &p) { return getCatScriptPath(p) + ARGS; } + + std::string getCatScriptPath(const CatalystProps &p) + { + return CATALYST + FS + SCRIPTS + FS + std::to_string(p.catalystPipelineID) + FS; + } + + std::string getCatStatePath() { return CATALYST + FS + STATE + FS; } + + std::string getCatChannelsPath() { return CATALYST + FS + CHANNELS + FS; } + + private: + CatalystManager(); + ~CatalystManager(); + CatalystManager(const CatalystManager &) = delete; + CatalystManager &operator=(const CatalystManager &) = delete; + + void broadCastString(std::string &s, const Ioss::ParallelUtils &putils); + void broadCastStatusCode(bool &statusCode, const Ioss::ParallelUtils &putils); + + void incrementOutputCounts(); + + CatalystPipelineID catalystOutputIDNumber; + std::map catPipes; + mState managerState; + }; +} // namespace Iocatalyst + +#endif \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.C b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.C index 425e706fc8..d60d2ae5c5 100644 --- a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.C +++ b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.C @@ -1,13 +1,12 @@ -// Copyright(C) 1999-2021, 2023 National Technology & Engineering Solutions +// Copyright(C) 1999-2021 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // // See packages/seacas/LICENSE for details +#include #include -#include "Ioss_Assembly.h" // for Assembly -#include "Ioss_CodeTypes.h" // for HAVE_MPI #include "Ioss_CommSet.h" // for CommSet #include "Ioss_DBUsage.h" // for DatabaseUsage, etc #include "Ioss_DatabaseIO.h" // for DatabaseIO @@ -15,7 +14,6 @@ #include "Ioss_EdgeSet.h" // for EdgeSet #include "Ioss_ElementBlock.h" // for ElementBlock #include "Ioss_ElementSet.h" // for ElementSet -#include "Ioss_ElementTopology.h" // for NameList #include "Ioss_EntityType.h" // for EntityType::ELEMENTBLOCK #include "Ioss_FaceBlock.h" // for FaceBlock #include "Ioss_FaceSet.h" // for FaceSet @@ -23,16 +21,23 @@ #include "Ioss_Map.h" // for Map, MapContainer #include "Ioss_NodeBlock.h" // for NodeBlock #include "Ioss_NodeSet.h" // for NodeSet -#include "Ioss_ParallelUtils.h" // for ParallelUtils, etc #include "Ioss_Property.h" // for Property -#include "Ioss_Region.h" // for Region -#include "Ioss_SerializeIO.h" // for SerializeIO #include "Ioss_SideBlock.h" // for SideBlock -#include "Ioss_StructuredBlock.h" // for StructuredBlock - -#include "Ioss_Utils.h" // for Utils, IOSS_ERROR, etc +#include // for Assembly +#include // for Blob +#include // for HAVE_MPI +#include // for NameList +#include // for ParallelUtils, etc +#include // for Region +#include // for SerializeIO +#include // for StructuredBlock + +#include // for Utils, IOSS_ERROR, etc +#include #include +#include #include +#include #include #include @@ -45,9 +50,103 @@ namespace Iocatalyst { namespace detail { - class FieldNonExistent + inline static const std::string ASSEMBLIES = "assemblies"; + inline static const std::string BLOBS = "blobs"; + inline static const std::string COMMSETS = "commsets"; + inline static const std::string EDGEBLOCKS = "edgeblocks"; + inline static const std::string EDGESETS = "edgesets"; + inline static const std::string ELEMENTBLOCKS = "elementblocks"; + inline static const std::string ELEMENTSETS = "elementsets"; + inline static const std::string FACEBLOCKS = "faceblocks"; + inline static const std::string FACESETS = "facesets"; + inline static const std::string NODEBLOCKS = "nodeblocks"; + inline static const std::string NODESETS = "nodesets"; + inline static const std::string REGION = "region"; + inline static const std::string SIDESETS = "sidesets"; + inline static const std::string STRUCTUREDBLOCKS = "structuredblocks"; + + inline static const std::string BLOCKLOCNODEIND = "blocklocalnodeindex"; + inline static const std::string BOUNDARYCONDS = "boundaryconditions"; + inline static const std::string CATCONDNODE = "CATALYST_CONDUIT_NODE"; + inline static const std::string CATDUMPDIR = "CATALYST_DATA_DUMP_DIRECTORY"; + inline static const std::string COMPONENTCOUNT = "component_count"; + inline static const std::string COMPONENTDEGREE = "component_degree"; + inline static const std::string COUNT = "count"; + inline static const std::string CONNECTIVITY = "connectivity"; + inline static const std::string CONNECTIVITYRAW = "connectivity_raw"; + inline static const char DASH_CHAR = '-'; + inline static const std::string DATABASE = "database"; + inline static const std::string DOT = "."; + inline static const std::string ENTITYCOUNT = "entity_count"; + inline static const std::string ENTITYTYPE = "entity_type"; + inline static const std::string EXECUTE_INVC = "execute_invc"; + inline static const std::string FIELDS = "fields"; + inline static const std::string FS = "/"; + inline static const char FS_CHAR = '/'; + inline static const std::string GLOBALIDMAP = "globalidmap"; + inline static const std::string KEY = "key"; + inline static const std::string INTBYTESIZEAPI = "int_byte_size_api"; + inline static const std::string IOSSCONTAINEDIN = "IOSS_INTERNAL_CONTAINED_IN"; + inline static const std::string MEMBERS = "members"; + inline static const std::string MEMBER_TYPE = "member_type"; + inline static const std::string MESHMODCO = "mesh_model_coordinates"; + inline static const std::string MESHMODCOX = "mesh_model_coordinates_x"; + inline static const std::string MESHMODCOY = "mesh_model_coordinates_y"; + inline static const std::string MESHMODCOZ = "mesh_model_coordinates_z"; + inline static const std::string NAME = "name"; + inline static const std::string NI = "ni"; + inline static const std::string NJ = "nj"; + inline static const std::string NK = "nk"; + inline static const std::string NIGLOBAL = "ni_global"; + inline static const std::string NJGLOBAL = "nj_global"; + inline static const std::string NKGLOBAL = "nk_global"; + inline static const std::string NODEBLOCKONE = "nodeblock_1"; + inline static const std::string IDS = "ids"; + inline static const std::string INDEX = "index"; + inline static const std::string OFFSET_I = "offset_i"; + inline static const std::string OFFSET_J = "offset_j"; + inline static const std::string OFFSET_K = "offset_k"; + inline static const std::string ORIGIN = "origin"; + inline static const std::string PARAMS_CONDUIT_BIN = "_params.conduit_bin."; + inline static const std::string PARENTTOPOLOGYTYPE = "parent_topology_type"; + inline static const std::string PROPERTIES = "properties"; + inline static const std::string REGION_ZERO = "region_0"; + inline static const std::string ROLE = "role"; + inline static const std::string SHALLOWCOPYFIELDS = "SHALLOW_COPY_FIELDS"; + inline static const std::string SIDEBLOCKS = "sideblocks"; + inline static const std::string STATETIME = "state_time"; + inline static const std::string STORAGE = "storage"; + inline static const std::string TIME = "time"; + inline static const std::string TOPOLOGYTYPE = "topology_type"; + inline static const std::string TYPE = "type"; + inline static const std::string VALUE = "value"; + inline static const std::string ZONECONNECTIVITY = "zoneconnectivity"; + + inline static const std::string CONNECTIONNAME = "m_connectionName"; + inline static const std::string DONORNAME = "m_donorName"; + inline static const std::string TRANSFORM = "m_transform"; + inline static const std::string OWNERRANGEBEG = "m_ownerRangeBeg"; + inline static const std::string OWNERRANGEEND = "m_ownerRangeEnd"; + inline static const std::string OWNEROFFSET = "m_ownerOffset"; + inline static const std::string DONORRANGEBEG = "m_donorRangeBeg"; + inline static const std::string DONORRANGEEND = "m_donorRangeEnd"; + inline static const std::string DONOROFFSET = "m_donorOffset"; + inline static const std::string OWNERZONE = "m_ownerZone"; + inline static const std::string DONORZONE = "m_donorZone"; + inline static const std::string FROMDECOMP = "m_fromDecomp"; + + inline static const std::string BCNAME = "m_bcName"; + inline static const std::string FAMNAME = "m_famName"; + inline static const std::string RANGEBEG = "m_rangeBeg"; + inline static const std::string RANGEEND = "m_rangeEnd"; + inline static const std::string FACE = "m_face"; + + std::string getValuePath(const std::string &prop) { - }; + return detail::PROPERTIES + detail::FS + prop + detail::FS + detail::VALUE; + } + + std::string getAPISizePath() { return detail::DATABASE + detail::FS + detail::INTBYTESIZEAPI; } template GroupingEntityT *createEntityGroup(const conduit_cpp::Node &node, Ioss::DatabaseIO *dbase); @@ -56,47 +155,141 @@ namespace Iocatalyst { Ioss::NodeBlock *createEntityGroup(const conduit_cpp::Node &node, Ioss::DatabaseIO *dbase) { - const auto name = node.name(); - return new Ioss::NodeBlock(dbase, name, node["properties/entity_count/value"].as_int64(), - node["properties/component_degree/value"].as_int64()); + return new Ioss::NodeBlock(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64(), + node[getValuePath(detail::COMPONENTDEGREE)].as_int64()); } template <> Ioss::ElementBlock *createEntityGroup(const conduit_cpp::Node &node, Ioss::DatabaseIO *dbase) { - const auto name = node.name(); - return new Ioss::ElementBlock(dbase, name, - node["properties/original_topology_type/value"].as_string(), - node["properties/entity_count/value"].as_int64()); + return new Ioss::ElementBlock(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::TOPOLOGYTYPE)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); } template <> Ioss::NodeSet *createEntityGroup(const conduit_cpp::Node &node, Ioss::DatabaseIO *dbase) { - const auto name = node.name(); - return new Ioss::NodeSet(dbase, name, node["properties/entity_count/value"].as_int64()); + return new Ioss::NodeSet(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::SideBlock *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::SideBlock(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::TOPOLOGYTYPE)].as_string(), + node[getValuePath(detail::PARENTTOPOLOGYTYPE)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); } template <> Ioss::SideSet *createEntityGroup(const conduit_cpp::Node &node, Ioss::DatabaseIO *dbase) { - const auto name = node.name(); - return new Ioss::SideSet(dbase, name); + return new Ioss::SideSet(dbase, node[getValuePath(detail::NAME)].as_string()); + } + + template <> + Ioss::StructuredBlock *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + Ioss::IJK_t localSizes = {{(int)node[getValuePath(detail::NI)].as_int64(), + (int)node[getValuePath(detail::NJ)].as_int64(), + (int)node[getValuePath(detail::NK)].as_int64()}}; + Ioss::IJK_t globalSizes = {{(int)node[getValuePath(detail::NIGLOBAL)].as_int64(), + (int)node[getValuePath(detail::NJGLOBAL)].as_int64(), + (int)node[getValuePath(detail::NKGLOBAL)].as_int64()}}; + Ioss::IJK_t parentOffsets = {{(int)node[getValuePath(detail::OFFSET_I)].as_int64(), + (int)node[getValuePath(detail::OFFSET_J)].as_int64(), + (int)node[getValuePath(detail::OFFSET_K)].as_int64()}}; + return new Ioss::StructuredBlock(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::COMPONENTDEGREE)].as_int64(), + localSizes, parentOffsets, globalSizes); + } + + template <> + Ioss::Assembly *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::Assembly(dbase, node[getValuePath(detail::NAME)].as_string()); + } + + template <> + Ioss::Blob *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::Blob(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::EdgeBlock *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::EdgeBlock(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::TOPOLOGYTYPE)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::FaceBlock *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::FaceBlock(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::TOPOLOGYTYPE)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::ElementSet *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::ElementSet(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::EdgeSet *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::EdgeSet(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::FaceSet *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::FaceSet(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); + } + + template <> + Ioss::CommSet *createEntityGroup(const conduit_cpp::Node &node, + Ioss::DatabaseIO *dbase) + { + return new Ioss::CommSet(dbase, node[getValuePath(detail::NAME)].as_string(), + node[getValuePath(detail::ENTITYTYPE)].as_string(), + node[getValuePath(detail::ENTITYCOUNT)].as_int64()); } } // namespace detail class DatabaseIO::ImplementationT { - conduit_cpp::Node Root; - conduit_cpp::Node DBNode; - mutable Ioss::Map NodeMap; + conduit_cpp::Node Root; + conduit_cpp::Node DBNode; + mutable Ioss::Map NodeMap; + std::map sideBlocks; public: conduit_cpp::Node &databaseNode() { return this->DBNode; } + void *catalystConduitNode() { return conduit_cpp::c_node(&this->DBNode); } void setDatabaseNode(conduit_node *c_node) { this->DBNode = conduit_cpp::Node(); @@ -117,122 +310,112 @@ namespace Iocatalyst { auto &node = this->DBNode; node = conduit_cpp::Node(); - node["database/int_byte_size_api"].set_int8(region->get_database()->int_byte_size_api()); - - this->defineEntityGroup(node["node_blocks"], region->get_node_blocks()); - this->defineEntityGroup(node["edge_blocks"], region->get_edge_blocks()); - this->defineEntityGroup(node["face_blocks"], region->get_face_blocks()); - this->defineEntityGroup(node["element_blocks"], region->get_element_blocks()); - // TODO: need to handle side-blocks. - this->defineEntityGroup(node["sidesets"], region->get_sidesets()); - this->defineEntityGroup(node["nodesets"], region->get_nodesets()); - this->defineEntityGroup(node["edgesets"], region->get_edgesets()); - this->defineEntityGroup(node["facesets"], region->get_facesets()); - this->defineEntityGroup(node["elementsets"], region->get_elementsets()); - this->defineEntityGroup(node["structured_blocks"], region->get_structured_blocks()); - this->defineEntityGroup(node["assemblies"], region->get_assemblies()); + node[detail::getAPISizePath()].set_int8(region->get_database()->int_byte_size_api()); + RegionContainer rc; + rc.push_back(region); + this->defineEntityGroup(node[detail::REGION], rc); + this->defineEntityGroup(node[detail::NODEBLOCKS], region->get_node_blocks()); + this->defineEntityGroup(node[detail::EDGEBLOCKS], region->get_edge_blocks()); + this->defineEntityGroup(node[detail::FACEBLOCKS], region->get_face_blocks()); + this->defineEntityGroup(node[detail::ELEMENTBLOCKS], region->get_element_blocks()); + this->defineEntityGroup(node[detail::SIDESETS], region->get_sidesets()); + this->defineEntityGroup(node[detail::NODESETS], region->get_nodesets()); + this->defineEntityGroup(node[detail::EDGESETS], region->get_edgesets()); + this->defineEntityGroup(node[detail::FACESETS], region->get_facesets()); + this->defineEntityGroup(node[detail::ELEMENTSETS], region->get_elementsets()); + this->defineEntityGroup(node[detail::STRUCTUREDBLOCKS], region->get_structured_blocks()); + this->defineEntityGroup(node[detail::ASSEMBLIES], region->get_assemblies()); + this->defineEntityGroup(node[detail::BLOBS], region->get_blobs()); + this->defineEntityGroup(node[detail::COMMSETS], region->get_commsets()); return true; } - bool readModel(Ioss::Region *region) - { - auto &node = this->DBNode; - region->get_database()->set_int_byte_size_api( - static_cast(node["database/int_byte_size_api"].as_int8())); - this->readEntityGroup(node["node_blocks"], region); - this->readEntityGroup(node["element_blocks"], region); - // this->readEntityGroup(node["edge_blocks"], region); - // this->readEntityGroup(node["face_blocks"], region); - // this->readEntityGroup(node["sidesets"], region); - // this->readEntityGroup(node["nodesets"], region); - // this->readEntityGroup(node["edgesets"], region); - // this->readEntityGroup(node["facesets"], region); - // this->readEntityGroup(node["elementsets"], region); - // this->readEntityGroup(node["structured_blocks"], region); - // this->readEntityGroup(node["assemblies"], region); - - return this->readTime(region); - } + void readZoneConnectivity(conduit_cpp::Node &&parent, Ioss::StructuredBlock *sb); + void readBoundaryConditions(conduit_cpp::Node &&parent, Ioss::StructuredBlock *sb); + Ioss::IJK_t readIJK(conduit_cpp::Node &&parent); + + bool readModel(Ioss::Region *region); bool readTime(Ioss::Region *region) { - auto &node = this->DBNode; - const auto time = node["state_time"].as_float64(); - region->add_state(time); + auto &node = this->DBNode; + if (node.has_child(detail::STATETIME)) { + const auto time = node[detail::STATETIME].as_float64(); + region->add_state(time); + } return true; } int64_t putField(const std::string &containerName, const Ioss::GroupingEntity *entityGroup, const Ioss::Field &field, void *data, size_t data_size, bool deep_copy) { - const auto groupName = entityGroup->generic_name(); + const auto groupName = getName(entityGroup); const auto num_to_get = field.verify(data_size); const auto num_components = field.raw_storage()->component_count(); if (num_to_get > 0) { - auto &&node = this->DBNode[containerName + "/" + groupName + "/fields/" + field.get_name()]; - node["role"].set(static_cast(field.get_role())); - node["type"].set(static_cast(field.get_type())); - node["count"].set(static_cast(field.verify(data_size))); - node["index"].set(static_cast(field.get_index())); - node["component_count"].set(static_cast(num_components)); - node["storage"].set(field.raw_storage()->name()); + auto &&node = this->DBNode[getFieldPath(containerName, groupName, field.get_name())]; + node[detail::ROLE].set(static_cast(field.get_role())); + node[detail::TYPE].set(static_cast(field.get_type())); + node[detail::COUNT].set(static_cast(field.verify(data_size))); + node[detail::INDEX].set(static_cast(field.get_index())); + node[detail::COMPONENTCOUNT].set(static_cast(num_components)); + node[detail::STORAGE].set(field.raw_storage()->name()); switch (field.get_type()) { case Ioss::Field::BasicType::DOUBLE: if (deep_copy) { - node["value"].set(static_cast(data), num_to_get * num_components); + node[detail::VALUE].set(static_cast(data), num_to_get * num_components); } else { - node["value"].set_external(static_cast(data), num_to_get * num_components); + node[detail::VALUE].set_external(static_cast(data), + num_to_get * num_components); } break; case Ioss::Field::BasicType::INT32: if (deep_copy) { - node["value"].set(static_cast(data), num_to_get * num_components); + node[detail::VALUE].set(static_cast(data), num_to_get * num_components); } else { - node["value"].set_external(static_cast(data), - num_to_get * num_components); + node[detail::VALUE].set_external(static_cast(data), + num_to_get * num_components); } break; case Ioss::Field::BasicType::INT64: if (deep_copy) { - node["value"].set(static_cast(data), num_to_get * num_components); + node[detail::VALUE].set(static_cast(data), num_to_get * num_components); } else { - node["value"].set_external(static_cast(data), - num_to_get * num_components); + node[detail::VALUE].set_external(static_cast(data), + num_to_get * num_components); } break; case Ioss::Field::BasicType::CHARACTER: if (deep_copy) { - node["value"].set(static_cast(data), num_to_get * num_components); + node[detail::VALUE].set(static_cast(data), num_to_get * num_components); } else { - node["value"].set_external(static_cast(data), - num_to_get * num_components); + node[detail::VALUE].set_external(static_cast(data), + num_to_get * num_components); } break; default: - fmt::print(stderr, "ERROR in {} {}: {} ({}), unsupported field type: {}\n", __func__, + std::ostringstream errmsg; + fmt::print(errmsg, "ERROR in {} {}: {} ({}), unsupported field type: {}\n", __func__, containerName, field.get_name(), num_to_get, field.type_string()); + IOSS_ERROR(errmsg); } } - fmt::print(stderr, "put_field {}: {} ({})\n", containerName, field.get_name(), num_to_get); return num_to_get; } int64_t getField(const std::string &containerName, const Ioss::GroupingEntity *entityGroup, const Ioss::Field &field, void *data, size_t data_size) { - const auto groupName = entityGroup->generic_name(); + const auto groupName = getName(entityGroup); auto num_to_get = field.verify(data_size); const auto num_components = field.raw_storage()->component_count(); if (num_to_get > 0) { - auto path = containerName + "/" + groupName + "/fields/" + field.get_name() + "/value"; - if (!this->DBNode.has_path(path)) { - throw detail::FieldNonExistent(); - ; - } + auto path = + getFieldPath(containerName, groupName, field.get_name()) + detail::FS + detail::VALUE; const auto &&node = this->DBNode[path]; switch (field.get_type()) { case Ioss::Field::BasicType::DOUBLE: @@ -255,30 +438,162 @@ namespace Iocatalyst { num_to_get * num_components, reinterpret_cast(data)); break; default: - fmt::print(stderr, "ERROR in {} {}: {} ({}), unsupported field type: {}\n", __func__, + std::ostringstream errmsg; + fmt::print(errmsg, "ERROR in {} {}: {} ({}), unsupported field type: {}\n", __func__, + containerName, field.get_name(), num_to_get, field.type_string()); + IOSS_ERROR(errmsg); + } + } + return num_to_get; + } + + int64_t getFieldZeroCopy(const std::string &containerName, + const Ioss::GroupingEntity *entityGroup, const Ioss::Field &field, + void **data, size_t *data_size) + + { + *data = nullptr; + *data_size = 0; + if (!hasField(containerName, entityGroup, field.get_name())) { + fmt::print(Ioss::OUTPUT(), "WARNING in {} : {}\n", __func__, + "field not available, " + field.get_name() + ", in container " + containerName + + "\n"); + return -1; + } + + const auto groupName = getName(entityGroup); + auto num_to_get = field.verify(0); + const auto num_components = field.raw_storage()->component_count(); + if (num_to_get > 0) { + auto path = + getFieldPath(containerName, groupName, field.get_name()) + detail::FS + detail::VALUE; + + const auto &&node = this->DBNode[path]; + *data_size = num_to_get * num_components; + switch (field.get_type()) { + case Ioss::Field::BasicType::DOUBLE: + *data = const_cast(node.as_double_ptr()); + break; + + case Ioss::Field::BasicType::INT32: + *data = const_cast(node.as_int32_ptr()); + break; + + case Ioss::Field::BasicType::INT64: + *data = const_cast(node.as_int64_ptr()); + break; + + case Ioss::Field::BasicType::CHARACTER: + *data = const_cast(node.as_char_ptr()); + break; + default: + std::ostringstream errmsg; + fmt::print(errmsg, "ERROR in {} {}: {} ({}), unsupported field type: {}\n", __func__, containerName, field.get_name(), num_to_get, field.type_string()); + IOSS_ERROR(errmsg); } } - fmt::print(stderr, "get_field {}: {} ({})\n", containerName, field.get_name(), num_to_get); return num_to_get; } + int64_t getMeshModelCoordinates(const std::string &containerName, + const Ioss::GroupingEntity *entityGroup, + const Ioss::Field &field, void *data, size_t data_size) + { + const auto groupName = getName(entityGroup); + auto num_to_get = field.verify(data_size); + const auto num_components = field.raw_storage()->component_count(); + if (num_to_get > 0) { + auto path = getPropertyPath(containerName, groupName, detail::COMPONENTDEGREE) + + detail::FS + detail::VALUE; + int64_t component_degree = this->DBNode[path].as_int64(); + double *rdata = static_cast(data); + + auto coord_lambda = [&](const std::string &coord_name, int ordinal) { + path = getFieldPath(containerName, groupName, coord_name) + detail::FS + detail::COUNT; + int64_t count = this->DBNode[path].as_int64(); + + path = getFieldPath(containerName, groupName, coord_name) + detail::FS + detail::VALUE; + const double *mesh_coords = + reinterpret_cast(this->DBNode[path].element_ptr(0)); + + for (size_t i = 0; i < count; i++) { + rdata[component_degree * i + ordinal] = mesh_coords[i]; + } + }; + + coord_lambda(detail::MESHMODCOX, 0); + + if (component_degree >= 2) { + coord_lambda(detail::MESHMODCOY, 1); + } + + if (component_degree == 3) { + coord_lambda(detail::MESHMODCOZ, 2); + } + } + return num_to_get; + } + + bool hasField(const std::string &containerName, const Ioss::GroupingEntity *entityGroup, + const std::string &fieldName) + { + const auto groupName = getName(entityGroup); + return this->DBNode.has_path(getFieldPath(containerName, groupName, fieldName)); + } + + std::string getFieldPath(const std::string &containerName, const std::string &groupName, + const std::string &fieldName) + { + return containerName + detail::FS + groupName + detail::FS + detail::FIELDS + detail::FS + + fieldName; + } + + bool hasProperty(const std::string &containerName, const Ioss::GroupingEntity *entityGroup, + const std::string &propertyName) + { + const auto groupName = getName(entityGroup); + return this->DBNode.has_path(getPropertyPath(containerName, groupName, propertyName)); + } + + std::string getPropertyPath(const std::string &containerName, const std::string &groupName, + const std::string &propertyName) + { + return containerName + detail::FS + groupName + detail::FS + detail::PROPERTIES + detail::FS + + propertyName; + } + + std::string getName(const Ioss::GroupingEntity *entityGroup) + { + std::string retVal = entityGroup->name(); + if (dynamic_cast(entityGroup) != nullptr) { + retVal = detail::REGION_ZERO; + } + else if (retVal.empty()) { + retVal = entityGroup->generic_name(); + } + std::replace(retVal.begin(), retVal.end(), detail::FS_CHAR, detail::DASH_CHAR); + return retVal; + } + Ioss::Map &get_node_map(const Ioss::DatabaseIO *dbase) const { if (this->NodeMap.defined()) { return this->NodeMap; } - auto &&idsNode = this->DBNode["node_blocks/nodeblock_1/fields/ids"]; - auto node_ids = const_cast(idsNode["value"].element_ptr(0)); - this->NodeMap.set_size(idsNode["count"].as_int64()); - if (idsNode["type"].as_int8() == Ioss::Field::BasicType::INT32) { - this->NodeMap.set_map(reinterpret_cast(node_ids), idsNode["count"].as_int64(), - 0); + auto nbone_path = detail::NODEBLOCKS + detail::FS + detail::NODEBLOCKONE + detail::FS + + detail::FIELDS + detail::FS + detail::IDS; + auto &&idsNode = this->DBNode[nbone_path]; + auto node_ids = const_cast(idsNode[detail::VALUE].element_ptr(0)); + this->NodeMap.set_size(idsNode[detail::COUNT].as_int64()); + if (idsNode[detail::TYPE].as_int8() == Ioss::Field::BasicType::INT32) { + this->NodeMap.set_map(reinterpret_cast(node_ids), + idsNode[detail::COUNT].as_int64(), 0); } - if (idsNode["type"].as_int8() == Ioss::Field::BasicType::INT64) { - this->NodeMap.set_map(reinterpret_cast(node_ids), idsNode["count"].as_int64(), - 0); + if (idsNode[detail::TYPE].as_int8() == Ioss::Field::BasicType::INT64) { + this->NodeMap.set_map(reinterpret_cast(node_ids), + idsNode[detail::COUNT].as_int64(), 0); } this->NodeMap.set_defined(true); @@ -291,11 +606,106 @@ namespace Iocatalyst { const std::vector &container) { for (auto group : container) { - this->addProperties(parent[group->generic_name()], group); + this->addProperties(parent[getName(group)], group); + } + return true; + } + + bool defineEntityGroup(conduit_cpp::Node parent, const Ioss::SideSetContainer &container) + { + for (auto group : container) { + this->addProperties(parent[getName(group)], group); + for (auto sb : group->get_side_blocks()) { + parent[getName(group) + detail::FS + detail::SIDEBLOCKS].append().set(sb->name()); + } + auto &node = this->DBNode; + this->defineEntityGroup(node[detail::SIDEBLOCKS], group->get_side_blocks()); + } + return true; + } + + bool defineEntityGroup(conduit_cpp::Node parent, const Ioss::AssemblyContainer &container) + { + for (auto group : container) { + this->addProperties(parent[getName(group)], group); + parent[getName(group) + detail::FS + detail::MEMBER_TYPE].set(group->get_member_type()); + for (auto as : group->get_members()) { + parent[getName(group) + detail::FS + detail::MEMBERS].append().set(as->name()); + } } return true; } + bool defineEntityGroup(conduit_cpp::Node parent, + const Ioss::StructuredBlockContainer &container) + { + for (auto group : container) { + this->addProperties(parent[getName(group)], group); + conduit_cpp::Node n; + for (auto zc : group->m_zoneConnectivity) { + defineZoneConnectivity(n, zc); + } + parent[getName(group) + detail::FS + detail::ZONECONNECTIVITY].set(n); + + n.set_node(conduit_cpp::Node()); + for (auto bc : group->m_boundaryConditions) { + defineBoundaryCondition(n, bc); + } + parent[getName(group) + detail::FS + detail::BOUNDARYCONDS].set(n); + + parent[getName(group) + detail::FS + detail::BLOCKLOCNODEIND].set( + group->m_blockLocalNodeIndex); + + n.set_node(conduit_cpp::Node()); + for (auto gm : group->m_globalIdMap) { + conduit_cpp::Node m; + m[detail::KEY] = gm.first; + m[detail::VALUE] = gm.second; + m.append().set(n); + } + parent[getName(group) + detail::FS + detail::GLOBALIDMAP].set(n); + } + return true; + } + + void defineZoneConnectivity(conduit_cpp::Node parent, Ioss::ZoneConnectivity &zc) + { + conduit_cpp::Node n; + n[detail::CONNECTIONNAME] = zc.m_connectionName; + n[detail::DONORNAME] = zc.m_donorName; + n[detail::TRANSFORM] = defineIJK(zc.m_transform); + n[detail::OWNERRANGEBEG] = defineIJK(zc.m_ownerRangeBeg); + n[detail::OWNERRANGEEND] = defineIJK(zc.m_ownerRangeEnd); + n[detail::OWNEROFFSET] = defineIJK(zc.m_ownerOffset); + n[detail::DONORRANGEBEG] = defineIJK(zc.m_donorRangeBeg); + n[detail::DONORRANGEEND] = defineIJK(zc.m_donorRangeEnd); + n[detail::DONOROFFSET] = defineIJK(zc.m_donorOffset); + n[detail::OWNERZONE] = zc.m_ownerZone; + n[detail::DONORZONE] = zc.m_donorZone; + n[detail::FROMDECOMP] = zc.m_fromDecomp; + parent.append().set(n); + } + + void defineBoundaryCondition(conduit_cpp::Node parent, Ioss::BoundaryCondition &bc) + { + conduit_cpp::Node n; + n[detail::BCNAME] = bc.m_bcName; + n[detail::FAMNAME] = bc.m_famName; + n[detail::RANGEBEG] = defineIJK(bc.m_rangeBeg); + n[detail::RANGEEND] = defineIJK(bc.m_rangeEnd); + n[detail::FACE] = bc.m_face; + parent.append().set(n); + } + + conduit_cpp::Node defineIJK(Ioss::IJK_t &a) + { + conduit_cpp::Node n; + for (auto v : a) { + n.append().set(v); + } + return n; + } + template bool addProperties(conduit_cpp::Node parent, GroupingEntityT *entityGroup) { @@ -304,27 +714,30 @@ namespace Iocatalyst { entityGroup->property_describe(Ioss::Property::INTERNAL, &names); entityGroup->property_describe(Ioss::Property::EXTERNAL, &names); entityGroup->property_describe(Ioss::Property::ATTRIBUTE, &names); + entityGroup->property_describe(Ioss::Property::IMPLICIT, &names); - auto &&propertiesNode = parent["properties"]; + auto &&propertiesNode = parent[detail::PROPERTIES]; for (const auto &name : names) { auto property = entityGroup->get_property(name); auto &&node = propertiesNode[name]; - node["type"].set(static_cast(property.get_type())); - node["origin"].set(static_cast(property.get_origin())); + node[detail::TYPE].set(static_cast(property.get_type())); + node[detail::ORIGIN].set(static_cast(property.get_origin())); switch (property.get_type()) { - case Ioss::Property::BasicType::REAL: node["value"].set(property.get_real()); break; + case Ioss::Property::BasicType::REAL: node[detail::VALUE].set(property.get_real()); break; - case Ioss::Property::BasicType::INTEGER: node["value"].set(property.get_int()); break; + case Ioss::Property::BasicType::INTEGER: node[detail::VALUE].set(property.get_int()); break; - case Ioss::Property::BasicType::STRING: node["value"].set(property.get_string()); break; + case Ioss::Property::BasicType::STRING: + node[detail::VALUE].set(property.get_string()); + break; case Ioss::Property::BasicType::VEC_INTEGER: - node["value"].set(property.get_vec_int()); + node[detail::VALUE].set(property.get_vec_int()); break; case Ioss::Property::BasicType::VEC_DOUBLE: - node["value"].set(property.get_vec_double()); + node[detail::VALUE].set(property.get_vec_double()); break; case Ioss::Property::BasicType::POINTER: @@ -342,10 +755,10 @@ namespace Iocatalyst { auto &&child = parent[idx]; auto block = detail::createEntityGroup(child, region->get_database()); region->add(block); - this->readProperties(child["properties"], block); + this->readProperties(child[detail::PROPERTIES], block); // read fields (meta-data only) - this->readFields(child["fields"], block); + this->readFields(child[detail::FIELDS], block); } return true; } @@ -356,23 +769,39 @@ namespace Iocatalyst { for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { auto &&child = parent[idx]; const auto name = child.name(); - const auto origin = static_cast(child["origin"].as_int8()); - switch (child["type"].as_int8()) { + const auto origin = static_cast(child[detail::ORIGIN].as_int8()); + if (block->property_exists(name) && block->get_property(name).is_implicit()) { + continue; + } + switch (child[detail::TYPE].as_int8()) { // TODO: missing origin case Ioss::Property::BasicType::REAL: - block->property_add(Ioss::Property(name, child["value"].as_float64(), origin)); + block->property_add(Ioss::Property(name, child[detail::VALUE].as_float64(), origin)); break; case Ioss::Property::BasicType::INTEGER: - block->property_add(Ioss::Property(name, child["value"].as_int64(), origin)); + block->property_add(Ioss::Property(name, child[detail::VALUE].as_int64(), origin)); break; case Ioss::Property::BasicType::STRING: - block->property_add(Ioss::Property(name, child["value"].as_string(), origin)); + block->property_add(Ioss::Property(name, child[detail::VALUE].as_string(), origin)); break; - case Ioss::Property::BasicType::VEC_INTEGER: - case Ioss::Property::BasicType::VEC_DOUBLE: abort(); // TODO: + case Ioss::Property::BasicType::VEC_INTEGER: { + std::vector v(child[detail::VALUE].as_int_ptr(), + child[detail::VALUE].as_int_ptr() + + child[detail::VALUE].number_of_elements()); + block->property_add(Ioss::Property(name, v, origin)); + break; + } + + case Ioss::Property::BasicType::VEC_DOUBLE: { + std::vector v(child[detail::VALUE].as_double_ptr(), + child[detail::VALUE].as_double_ptr() + + child[detail::VALUE].number_of_elements()); + block->property_add(Ioss::Property(name, v, origin)); + break; + } } } return true; @@ -384,17 +813,23 @@ namespace Iocatalyst { for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { auto &&child = parent[idx]; const auto name = child.name(); - const auto type = static_cast(child["type"].as_int8()); - const auto role = static_cast(child["role"].as_int8()); - const auto count = child["count"].as_int64(); - const auto index = child["index"].as_int64(); - const auto storage = child["storage"].as_string(); + const auto type = static_cast(child[detail::TYPE].as_int8()); + const auto role = static_cast(child[detail::ROLE].as_int8()); + const auto count = child[detail::COUNT].as_int64(); + const auto index = child[detail::INDEX].as_int64(); + const auto storage = child[detail::STORAGE].as_string(); if (!block->field_exists(name)) { - block->field_add(Ioss::Field(name, type, storage, role, count, index)); + block->field_add( + Ioss::Field(name, type, storage, role, count, index).set_zero_copy_enabled()); } else { // TODO verify field details. - assert(block->get_field(name).get_type() == type); + auto field = block->get_fieldref(name); + if (!field.has_transform()) { + block->get_fieldref(name).set_zero_copy_enabled(); + } + assert(field.get_type() == type); + auto f = block->get_fieldref(name); } } @@ -402,6 +837,230 @@ namespace Iocatalyst { } }; + template <> + bool DatabaseIO::ImplementationT::readEntityGroup(conduit_cpp::Node &&parent, + Ioss::Region *region) + { + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + auto &&child = parent[idx]; + this->readProperties(child[detail::PROPERTIES], region); + + // read fields (meta-data only) + this->readFields(child[detail::FIELDS], region); + } + return true; + } + + template <> + bool DatabaseIO::ImplementationT::readEntityGroup(conduit_cpp::Node &&parent, + Ioss::Region *region) + { + sideBlocks.clear(); + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + auto &&child = parent[idx]; + auto block = detail::createEntityGroup(child, region->get_database()); + if (sideBlocks.find(block->name()) == sideBlocks.end()) { + sideBlocks[block->name()] = block; + } + else { + std::ostringstream errmsg; + fmt::print(errmsg, "ERROR in {} {}: side block name used twice.\n", __func__, + block->name()); + IOSS_ERROR(errmsg); + } + + this->readProperties(child[detail::PROPERTIES], block); + + // read fields (meta-data only) + this->readFields(child[detail::FIELDS], block); + } + return true; + } + + template <> + bool DatabaseIO::ImplementationT::readEntityGroup(conduit_cpp::Node &&parent, + Ioss::Region *region) + { + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + auto &&child = parent[idx]; + auto block = detail::createEntityGroup(child, region->get_database()); + for (int i = 0; i < child[detail::SIDEBLOCKS].number_of_children(); i++) { + auto name = child[detail::SIDEBLOCKS].child(i).as_string(); + if (sideBlocks.find(name) != sideBlocks.end()) { + block->add(sideBlocks[name]); + } + else { + std::ostringstream errmsg; + fmt::print(errmsg, "ERROR in {} {}: side block name not available.\n", __func__, name); + IOSS_ERROR(errmsg); + } + } + region->add(block); + this->readProperties(child[detail::PROPERTIES], block); + + // read fields (meta-data only) + this->readFields(child[detail::FIELDS], block); + } + sideBlocks.clear(); + return true; + } + + template <> + bool DatabaseIO::ImplementationT::readEntityGroup(conduit_cpp::Node &&parent, + Ioss::Region *region) + { + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + auto &&child = parent[idx]; + auto block = detail::createEntityGroup(child, region->get_database()); + auto member_type = child[detail::MEMBER_TYPE].as_int(); + for (int i = 0; i < child[detail::MEMBERS].number_of_children(); i++) { + auto name = child[detail::MEMBERS].child(i).as_string(); + Ioss::GroupingEntity *ge = nullptr; + switch (member_type) { + case Ioss::EntityType::NODEBLOCK: ge = region->get_node_block(name); break; + case Ioss::EntityType::EDGEBLOCK: ge = region->get_edge_block(name); break; + case Ioss::EntityType::EDGESET: ge = region->get_edgeset(name); break; + case Ioss::EntityType::FACEBLOCK: ge = region->get_face_block(name); break; + case Ioss::EntityType::ELEMENTBLOCK: ge = region->get_element_block(name); break; + case Ioss::EntityType::NODESET: ge = region->get_nodeset(name); break; + case Ioss::EntityType::FACESET: ge = region->get_faceset(name); break; + case Ioss::EntityType::ELEMENTSET: ge = region->get_elementset(name); break; + case Ioss::EntityType::SIDESET: ge = region->get_sideset(name); break; + case Ioss::EntityType::COMMSET: ge = region->get_commset(name); break; + case Ioss::EntityType::SIDEBLOCK: ge = region->get_sideblock(name); break; + case Ioss::EntityType::ASSEMBLY: ge = region->get_assembly(name); break; + case Ioss::EntityType::BLOB: ge = region->get_blob(name); break; + default: + std::ostringstream errmsg; + fmt::print(stderr, "ERROR in {} {}: unknown grouping entity type.\n", __func__, name); + IOSS_ERROR(errmsg); + } + if (ge) { + block->add(ge); + } + else { + std::ostringstream errmsg; + fmt::print(errmsg, "ERROR in {} {}: grouping entity not found.\n", __func__, name); + IOSS_ERROR(errmsg); + } + } + region->add(block); + this->readProperties(child[detail::PROPERTIES], block); + + // read fields (meta-data only) + this->readFields(child[detail::FIELDS], block); + } + return true; + } + + template <> + bool + DatabaseIO::ImplementationT::readEntityGroup(conduit_cpp::Node &&parent, + Ioss::Region *region) + { + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + auto &&child = parent[idx]; + auto block = detail::createEntityGroup(child, region->get_database()); + region->add(block); + auto parent = block->get_node_block().get_property(detail::IOSSCONTAINEDIN); + this->readProperties(child[detail::PROPERTIES], block); + this->readProperties( + child[getName(&block->get_node_block()) + detail::FS + detail::PROPERTIES], + &block->get_node_block()); + block->get_node_block().property_add(parent); + + // read fields (meta-data only) + this->readFields(child[detail::FIELDS], block); + this->readFields(child[getName(&block->get_node_block()) + detail::FS + detail::FIELDS], + &block->get_node_block()); + + readZoneConnectivity(child[detail::ZONECONNECTIVITY], block); + readBoundaryConditions(child[detail::BOUNDARYCONDS], block); + + conduit_uint64 *my_vals = child[detail::BLOCKLOCNODEIND].as_uint64_ptr(); + block->m_blockLocalNodeIndex.clear(); + for (int i = 0; i < child[detail::BLOCKLOCNODEIND].number_of_elements(); i++) { + block->m_blockLocalNodeIndex.push_back(my_vals[i]); + } + + conduit_cpp::Node &&n = child[detail::GLOBALIDMAP]; + block->m_globalIdMap.clear(); + for (conduit_index_t i = 0, m = n.number_of_children(); i < m; ++i) { + auto &&c = n[i]; + block->m_globalIdMap.push_back( + std::pair(c[detail::KEY].as_int(), c[detail::VALUE].as_int())); + } + } + return true; + } + + void DatabaseIO::ImplementationT::readZoneConnectivity(conduit_cpp::Node &&parent, + Ioss::StructuredBlock *sb) + { + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + auto &&child = parent[idx]; + Ioss::ZoneConnectivity zc( + child[detail::CONNECTIONNAME].as_string(), child[detail::OWNERZONE].as_int(), + child[detail::DONORNAME].as_string(), child[detail::DONORZONE].as_int(), + readIJK(child[detail::TRANSFORM]), readIJK(child[detail::OWNERRANGEBEG]), + readIJK(child[detail::OWNERRANGEEND]), readIJK(child[detail::OWNEROFFSET]), + readIJK(child[detail::DONORRANGEBEG]), readIJK(child[detail::DONORRANGEEND]), + readIJK(child[detail::DONOROFFSET])); + zc.m_fromDecomp = child[detail::FROMDECOMP].as_int(); + sb->m_zoneConnectivity.push_back(zc); + } + } + + void DatabaseIO::ImplementationT::readBoundaryConditions(conduit_cpp::Node &&parent, + Ioss::StructuredBlock *sb) + { + for (conduit_index_t idx = 0, max = parent.number_of_children(); idx < max; ++idx) { + + auto &&child = parent[idx]; + Ioss::BoundaryCondition bc( + child[detail::BCNAME].as_string(), child[detail::FAMNAME].as_string(), + readIJK(child[detail::RANGEBEG]), readIJK(child[detail::RANGEEND])); + bc.m_face = child[detail::FACE].as_int(); + sb->m_boundaryConditions.push_back(bc); + } + } + + Ioss::IJK_t DatabaseIO::ImplementationT::readIJK(conduit_cpp::Node &&parent) + { + Ioss::IJK_t a{{0, 0, 0}}; + for (auto i = 0; i < parent.number_of_children(); i++) { + a[i] = parent[i].as_int(); + } + return a; + } + + bool DatabaseIO::ImplementationT::readModel(Ioss::Region *region) + { + auto &node = this->DBNode; + region->get_database()->set_int_byte_size_api( + static_cast(node[detail::getAPISizePath()].as_int8())); + auto tpath = detail::REGION + detail::FS + detail::TIME; + if (node.has_path(tpath)) { + region->add_state(node[tpath].to_float64()); + } + this->readEntityGroup(node[detail::REGION], region); + this->readEntityGroup(node[detail::NODEBLOCKS], region); + this->readEntityGroup(node[detail::ELEMENTBLOCKS], region); + this->readEntityGroup(node[detail::EDGEBLOCKS], region); + this->readEntityGroup(node[detail::FACEBLOCKS], region); + this->readEntityGroup(node[detail::SIDEBLOCKS], region); + this->readEntityGroup(node[detail::SIDESETS], region); + this->readEntityGroup(node[detail::NODESETS], region); + this->readEntityGroup(node[detail::EDGESETS], region); + this->readEntityGroup(node[detail::FACESETS], region); + this->readEntityGroup(node[detail::ELEMENTSETS], region); + this->readEntityGroup(node[detail::STRUCTUREDBLOCKS], region); + this->readEntityGroup(node[detail::ASSEMBLIES], region); + this->readEntityGroup(node[detail::BLOBS], region); + this->readEntityGroup(node[detail::COMMSETS], region); + return true; + } + DatabaseIO::DatabaseIO(Ioss::Region *region, const std::string &filename, Ioss::DatabaseUsage db_usage, Ioss_MPI_Comm communicator, const Ioss::PropertyManager &props) @@ -410,75 +1069,53 @@ namespace Iocatalyst { { dbState = Ioss::STATE_UNKNOWN; - //// Always 64 bits - // dbIntSizeAPI = Ioss::USE_INT64_API; - dbIntSizeAPI = Ioss::USE_INT32_API; bool shallowCopy = false; - if (Ioss::Utils::check_set_bool_property(properties, "SHALLOW_COPY_FIELDS", shallowCopy)) { + if (Ioss::Utils::check_set_bool_property(properties, detail::SHALLOWCOPYFIELDS, shallowCopy)) { this->useDeepCopy = !shallowCopy; } if (is_input()) { auto &pm = get_property_manager(); - if (pm.exists("CATALYST_CONDUIT_NODE")) { + if (pm.exists(detail::CATCONDNODE)) { auto c_node_ptr = reinterpret_cast( - get_property_manager().get("CATALYST_CONDUIT_NODE").get_pointer()); + get_property_manager().get(detail::CATCONDNODE).get_pointer()); this->Impl->setDatabaseNode(c_node_ptr); } else { // we'll use filename as the location for the data dumps and read those. std::ostringstream path; - path << filename << "/execute_invc43_params.conduit_bin." << util().parallel_size() << "." + path << get_catalyst_dump_dir() << detail::EXECUTE_INVC << filename + << detail::PARAMS_CONDUIT_BIN << util().parallel_size() << detail::DOT << util().parallel_rank(); auto &root = this->Impl->root(); auto &dbase = this->Impl->databaseNode(); conduit_node_load(conduit_cpp::c_node(&root), path.str().c_str(), "conduit_bin"); - conduit_node_set_external_node( - conduit_cpp::c_node(&dbase), - conduit_node_fetch(conduit_cpp::c_node(&root), "catalyst/channels/dataset/data")); + auto dp = CatalystManager::getInstance().getCatDataPath(props); + conduit_node_set_external_node(conduit_cpp::c_node(&dbase), + conduit_node_fetch(conduit_cpp::c_node(&root), dp.c_str())); } } else { - // in output-mode, we're pass data on to Catalyst. - conduit_cpp::Node node; - -#if defined(SEACAS_HAVE_MPI) - // pass communicator is using MPI. - // TODO: skip for now. - // node["catalyst"]["mpi_comm"].set(MPI_Comm_c2f(communicator)); -#endif - - // TODO: Here, we need to pass pipeline scripts to execute to the Catalyst - // implementation. ParaView Catalyst supports multiple scripts with args. - // We could support that via the property manager. There are several - // options: - // - // 1. the simulation can add bunch of properties that indicate which scripts - // to run and we use those. - // 2. we could use the filename passed to the database as the - // configuration file that provides the scripts to runs. - // 3. we could simply treat the filename passed to the database as the - // pipeline script. - // - // Here, I am using the simplest option #3. I do that since that makes it - // easy for me to use existing tools like `io_shell` to test this database - node["catalyst"]["scripts"]["sample0"]["filename"].set(filename); - catalyst_initialize(conduit_cpp::c_node(&node)); + catPipeID = CatalystManager::getInstance().initialize(props, this->util()); } } DatabaseIO::~DatabaseIO() { if (!is_input()) { - conduit_cpp::Node node; - catalyst_finalize(conduit_cpp::c_node(&node)); + CatalystManager::getInstance().finalize(catPipeID); } } bool DatabaseIO::begin_nl(Ioss::State state) { this->dbState = state; + if (is_input()) { + if (state == Ioss::STATE_TRANSIENT) { + auto &impl = (*this->Impl.get()); + } + } return true; } @@ -502,7 +1139,6 @@ namespace Iocatalyst { case Ioss::STATE_MODEL: // here the model has meshdata e.g mesh fields, ids, coordinates etc. - // impl.print(); break; case Ioss::STATE_DEFINE_TRANSIENT: break; @@ -530,17 +1166,10 @@ namespace Iocatalyst { else { // invoke catalyst. auto &impl = (*this->Impl.get()); - - // state is 1-based, need to offset by 1 to make it 0-based. - // timesteps start with 0. + auto &dbaseNode = this->Impl->databaseNode(); + dbaseNode[detail::REGION + detail::FS + detail::TIME].set_float64(time); conduit_cpp::Node node; - node["catalyst/state/timestep"].set(state - 1); - node["catalyst/state/cycle"].set(state - 1); - node["catalyst/state/time"].set(time); - node["catalyst/channels/dataset/type"].set(std::string("ioss")); - node["catalyst/channels/dataset/data"].set_external(impl.databaseNode()); - node["catalyst/channels/dataset/data/state_time"].set(time); - catalyst_execute(conduit_cpp::c_node(&node)); + CatalystManager::getInstance().execute(catPipeID, state, time, impl.databaseNode()); } return true; } @@ -548,8 +1177,9 @@ namespace Iocatalyst { unsigned DatabaseIO::entity_field_support() const { return Ioss::NODEBLOCK | Ioss::EDGEBLOCK | Ioss::FACEBLOCK | Ioss::ELEMENTBLOCK | - Ioss::NODESET | Ioss::EDGESET | Ioss::FACESET | Ioss::ELEMENTSET | Ioss::SIDESET | - Ioss::SIDEBLOCK | Ioss::REGION; + Ioss::COMMSET | Ioss::NODESET | Ioss::EDGESET | Ioss::FACESET | Ioss::ELEMENTSET | + Ioss::SIDESET | Ioss::SIDEBLOCK | Ioss::STRUCTUREDBLOCK | Ioss::ASSEMBLY | Ioss::REGION | + Ioss::BLOB; } void DatabaseIO::read_meta_data_nl() @@ -570,120 +1200,186 @@ namespace Iocatalyst { impl.readTime(region); } - int64_t DatabaseIO::put_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, + void *DatabaseIO::get_catalyst_conduit_node() + { + auto &impl = (*this->Impl.get()); + return impl.catalystConduitNode(); + } + + void DatabaseIO::print_catalyst_conduit_node() + { + auto &impl = (*this->Impl.get()); + impl.print(); + } + + std::string DatabaseIO::get_catalyst_dump_dir() const + { + std::string retVal; + auto catalystDumpDir = std::getenv(detail::CATDUMPDIR.c_str()); + if (catalystDumpDir) { + retVal = catalystDumpDir; + } + if (!retVal.empty() && retVal.back() != detail::FS_CHAR) { + retVal += detail::FS_CHAR; + } + return retVal; + } + + int64_t DatabaseIO::put_field_internal(const Ioss::Region *reg, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("node_blocks", nb, field, data, data_size, this->deep_copy()); + return impl.putField(detail::REGION, reg, field, data, data_size, this->deep_copy()); + } + + int64_t DatabaseIO::put_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, + void *data, size_t data_size) const + { + auto &impl = (*this->Impl.get()); + std::string blockPath = detail::NODEBLOCKS; + if (nb->is_nonglobal_nodeblock()) { + blockPath = detail::STRUCTUREDBLOCKS + detail::FS + impl.getName(nb->contained_in()); + } + return impl.putField(blockPath, nb, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::EdgeBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("edge_blocks", eb, field, data, data_size, this->deep_copy()); + return impl.putField(detail::EDGEBLOCKS, eb, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::FaceBlock *fb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("face_blocks", fb, field, data, data_size, this->deep_copy()); + return impl.putField(detail::FACEBLOCKS, fb, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::ElementBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("element_blocks", eb, field, data, data_size, this->deep_copy()); + return impl.putField(detail::ELEMENTBLOCKS, eb, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::SideBlock *sb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("sideblocks", sb, field, data, data_size, this->deep_copy()); + return impl.putField(detail::SIDEBLOCKS, sb, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::NodeSet *ns, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("nodesets", ns, field, data, data_size, this->deep_copy()); + return impl.putField(detail::NODESETS, ns, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::EdgeSet *es, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("edgesets", es, field, data, data_size, this->deep_copy()); + return impl.putField(detail::EDGESETS, es, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::FaceSet *fs, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("facesets", fs, field, data, data_size, this->deep_copy()); + return impl.putField(detail::FACESETS, fs, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::ElementSet *es, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("elementsets", es, field, data, data_size, this->deep_copy()); + return impl.putField(detail::ELEMENTSETS, es, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::SideSet *ss, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("sidesets", ss, field, data, data_size, this->deep_copy()); + return impl.putField(detail::SIDESETS, ss, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::CommSet *cs, const Ioss::Field &field, void *data, size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.putField(detail::COMMSETS, cs, field, data, data_size, this->deep_copy()); } - int64_t DatabaseIO::put_field_internal(const Ioss::Assembly * /*as*/, - const Ioss::Field & /*field*/, void * /*data*/, - size_t /*data_size*/) const + int64_t DatabaseIO::put_field_internal(const Ioss::Assembly *as, const Ioss::Field &field, + void *data, size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.putField(detail::ASSEMBLIES, as, field, data, data_size, this->deep_copy()); } - int64_t DatabaseIO::put_field_internal(const Ioss::Blob * /*bl*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const + int64_t DatabaseIO::put_field_internal(const Ioss::Blob *bl, const Ioss::Field &field, void *data, + size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.putField(detail::BLOBS, bl, field, data, data_size, this->deep_copy()); } int64_t DatabaseIO::put_field_internal(const Ioss::StructuredBlock *sb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.putField("structured_blocks", sb, field, data, data_size, this->deep_copy()); + return impl.putField(detail::STRUCTUREDBLOCKS, sb, field, data, data_size, this->deep_copy()); + } + + int64_t DatabaseIO::get_field_internal(const Ioss::Region *reg, const Ioss::Field &field, + void *data, size_t data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getField(detail::REGION, reg, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("node_blocks", nb, field, data, data_size); + + std::string blockPath = detail::NODEBLOCKS; + if (nb->is_nonglobal_nodeblock()) { + blockPath = detail::STRUCTUREDBLOCKS + detail::FS + impl.getName(nb->contained_in()); + } + + if (impl.hasField(blockPath, nb, field.get_name())) { + return impl.getField(blockPath, nb, field, data, data_size); + } + else if ((field.get_name() == detail::MESHMODCO) && + (impl.hasField(blockPath, nb, detail::MESHMODCOX) && + impl.hasField(blockPath, nb, detail::MESHMODCOY) && + impl.hasField(blockPath, nb, detail::MESHMODCOZ))) { + return impl.getMeshModelCoordinates(blockPath, nb, field, data, data_size); + } + else { + fmt::print(Ioss::OUTPUT(), "WARNING in {} : {}\n", __func__, + "field not available, " + field.get_name() + ", in container " + blockPath + "\n"); + return -1; + } } int64_t DatabaseIO::get_field_internal(const Ioss::ElementBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - try { - return impl.getField("element_blocks", eb, field, data, data_size); + if (impl.hasField(detail::ELEMENTBLOCKS, eb, field.get_name())) { + return impl.getField(detail::ELEMENTBLOCKS, eb, field, data, data_size); } - catch (detail::FieldNonExistent &) { - if (field.get_name() == "connectivity_raw") { + else { + if (field.get_name() == detail::CONNECTIVITYRAW && + impl.hasField(detail::ELEMENTBLOCKS, eb, detail::CONNECTIVITY)) { // maybe the data has 'connectivity' provided, so we convert it to 'connectivity_raw'. - auto count = this->get_field_internal(eb, eb->get_field("connectivity"), data, data_size); + auto count = + this->get_field_internal(eb, eb->get_field(detail::CONNECTIVITY), data, data_size); if (count <= 0) { return count; } @@ -692,10 +1388,11 @@ namespace Iocatalyst { data, field, field.verify(data_size) * field.raw_storage()->component_count()); return count; } - else if (field.get_name() == "connectivity") { + else if (field.get_name() == detail::CONNECTIVITY && + impl.hasField(detail::ELEMENTBLOCKS, eb, detail::CONNECTIVITYRAW)) { // maybe the data has 'connectivity_raw' is provided, so we convert it to 'connectivity. auto count = - this->get_field_internal(eb, eb->get_field("connectivity_raw"), data, data_size); + this->get_field_internal(eb, eb->get_field(detail::CONNECTIVITYRAW), data, data_size); if (count <= 0) { return count; } @@ -704,6 +1401,10 @@ namespace Iocatalyst { data, field, field.verify(data_size) * field.raw_storage()->component_count()); return count; } + + fmt::print(Ioss::OUTPUT(), "WARNING in {} : {}\n", __func__, + "field not available, " + field.get_name() + ", in container " + + detail::ELEMENTBLOCKS + "\n"); return -1; } } @@ -712,71 +1413,186 @@ namespace Iocatalyst { void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("edge_blocks", eb, field, data, data_size); + return impl.getField(detail::EDGEBLOCKS, eb, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::FaceBlock *fb, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("face_blocks", fb, field, data, data_size); + return impl.getField(detail::FACEBLOCKS, fb, field, data, data_size); } - int64_t DatabaseIO::get_field_internal(const Ioss::SideBlock *fb, const Ioss::Field &field, + int64_t DatabaseIO::get_field_internal(const Ioss::SideBlock *sb, const Ioss::Field &field, void *data, size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.getField(detail::SIDEBLOCKS, sb, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::NodeSet *ns, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("nodesets", ns, field, data, data_size); + return impl.getField(detail::NODESETS, ns, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::EdgeSet *ns, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("edgesets", ns, field, data, data_size); + return impl.getField(detail::EDGESETS, ns, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::FaceSet *ns, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("facesets", ns, field, data, data_size); + return impl.getField(detail::FACESETS, ns, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::ElementSet *ns, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("elementsets", ns, field, data, data_size); + return impl.getField(detail::ELEMENTSETS, ns, field, data, data_size); } - int64_t DatabaseIO::get_field_internal(const Ioss::SideSet *fs, const Ioss::Field &field, + int64_t DatabaseIO::get_field_internal(const Ioss::SideSet *ss, const Ioss::Field &field, void *data, size_t data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("sidesets", fs, field, data, data_size); + return impl.getField(detail::SIDESETS, ss, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::CommSet *cs, const Ioss::Field &field, void *data, size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.getField(detail::COMMSETS, cs, field, data, data_size); } - int64_t DatabaseIO::get_field_internal(const Ioss::Assembly * /*as*/, - const Ioss::Field & /*field*/, void * /*data*/, - size_t /*data_size*/) const + int64_t DatabaseIO::get_field_internal(const Ioss::Assembly *as, const Ioss::Field &field, + void *data, size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.getField(detail::ASSEMBLIES, as, field, data, data_size); } - int64_t DatabaseIO::get_field_internal(const Ioss::Blob * /*bl*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const + int64_t DatabaseIO::get_field_internal(const Ioss::Blob *bl, const Ioss::Field &field, void *data, + size_t data_size) const { - return -1; + auto &impl = (*this->Impl.get()); + return impl.getField(detail::BLOBS, bl, field, data, data_size); } int64_t DatabaseIO::get_field_internal(const Ioss::StructuredBlock *sb, const Ioss::Field &field, void *data, size_t data_size) const + { + std::string blockPath = detail::STRUCTUREDBLOCKS; + auto &impl = (*this->Impl.get()); + if (impl.hasField(blockPath, sb, field.get_name())) { + return impl.getField(blockPath, sb, field, data, data_size); + } + else if ((field.get_name() == detail::MESHMODCO) && + (impl.hasField(blockPath, sb, detail::MESHMODCOX) && + impl.hasField(blockPath, sb, detail::MESHMODCOY) && + impl.hasField(blockPath, sb, detail::MESHMODCOZ))) { + return impl.getMeshModelCoordinates(blockPath, sb, field, data, data_size); + } + else { + fmt::print(Ioss::OUTPUT(), "WARNING in {} : {}\n", __func__, + "field not available, " + field.get_name() + ", in container " + + detail::STRUCTUREDBLOCKS + "\n"); + return -1; + } + } + + int64_t DatabaseIO::get_zc_field_internal(const Ioss::Region *reg, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::REGION, reg, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, + void **data, size_t *data_size) const + { + + auto &impl = (*this->Impl.get()); + std::string blockPath = detail::NODEBLOCKS; + if (nb->is_nonglobal_nodeblock()) { + blockPath = detail::STRUCTUREDBLOCKS + detail::FS + impl.getName(nb->contained_in()); + } + return impl.getFieldZeroCopy(blockPath, nb, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::EdgeBlock *eb, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::EDGEBLOCKS, eb, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::FaceBlock *fb, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::FACEBLOCKS, fb, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::ElementBlock *eb, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::ELEMENTBLOCKS, eb, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::SideBlock *sb, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::SIDEBLOCKS, sb, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::NodeSet *ns, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::NODESETS, ns, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::EdgeSet *es, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::EDGESETS, es, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::FaceSet *fs, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::FACESETS, fs, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::ElementSet *es, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::ELEMENTSETS, es, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::SideSet *ss, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::SIDESETS, ss, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::CommSet *cs, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::COMMSETS, cs, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::Assembly *as, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::ASSEMBLIES, as, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::Blob *bl, const Ioss::Field &field, + void **data, size_t *data_size) const + { + auto &impl = (*this->Impl.get()); + return impl.getFieldZeroCopy(detail::BLOBS, bl, field, data, data_size); + } + int64_t DatabaseIO::get_zc_field_internal(const Ioss::StructuredBlock *sb, + const Ioss::Field &field, void **data, + size_t *data_size) const { auto &impl = (*this->Impl.get()); - return impl.getField("structured_blocks", sb, field, data, data_size); + return impl.getFieldZeroCopy(detail::STRUCTUREDBLOCKS, sb, field, data, data_size); } } // namespace Iocatalyst diff --git a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.h b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.h index 04b3c676f6..c9602e7a5b 100644 --- a/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.h +++ b/packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.h @@ -15,6 +15,7 @@ #include "Ioss_SideSet.h" // for SideBlockContainer, SideSet #include "Ioss_Field.h" // for Field, etc +#include "Iocatalyst_CatalystManager.h" #include // for std::unique_ptr @@ -30,6 +31,8 @@ namespace Iocatalyst { Ioss_MPI_Comm communicator, const Ioss::PropertyManager &props); ~DatabaseIO() override; + using RegionContainer = std::vector; + // Check capabilities of input/output database... Returns an // unsigned int with the supported Ioss::EntityTypes or'ed // together. If "return_value & Ioss::EntityType" is set, then the @@ -76,6 +79,12 @@ namespace Iocatalyst { */ bool deep_copy() const { return this->useDeepCopy; } + void *get_catalyst_conduit_node(); + + void print_catalyst_conduit_node(); + + std::string get_catalyst_dump_dir() const; + private: bool open_group_nl(const std::string & /* group_name */) override { return false; } bool create_subgroup_nl(const std::string & /* group_name */) override { return false; } @@ -89,6 +98,8 @@ namespace Iocatalyst { bool begin_state_nl(int state, double time) override; bool end_state_nl(int state, double time) override; + CatalystManager::CatalystPipelineID catPipeID; + void compute_block_membership_nl(Ioss::SideBlock * /* efblock */, std::vector & /* block_membership */) const override @@ -96,72 +107,97 @@ namespace Iocatalyst { } int64_t get_field_internal(const Ioss::Region *reg, const Ioss::Field &field, void *data, - size_t data_size) const override - { - return -1; - } + size_t data_size) const override; int64_t get_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::EdgeBlock *nb, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::EdgeBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::FaceBlock *nb, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::FaceBlock *fb, const Ioss::Field &field, void *data, size_t data_size) const override; int64_t get_field_internal(const Ioss::ElementBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::SideBlock *fb, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::SideBlock *sb, const Ioss::Field &field, void *data, size_t data_size) const override; int64_t get_field_internal(const Ioss::NodeSet *ns, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::EdgeSet *ns, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::EdgeSet *es, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::FaceSet *ns, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::FaceSet *fs, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::ElementSet *ns, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::ElementSet *es, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::SideSet *fs, const Ioss::Field &field, void *data, + int64_t get_field_internal(const Ioss::SideSet *ss, const Ioss::Field &field, void *data, size_t data_size) const override; int64_t get_field_internal(const Ioss::CommSet *cs, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t get_field_internal(const Ioss::Assembly * /*as*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const override; - int64_t get_field_internal(const Ioss::Blob * /*bl*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const override; - int64_t get_field_internal(const Ioss::StructuredBlock * /*sb*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const override; + int64_t get_field_internal(const Ioss::Assembly *as, const Ioss::Field &field, void *data, + size_t data_size) const override; + int64_t get_field_internal(const Ioss::Blob *bl, const Ioss::Field &field, + void *data, size_t data_size) const override; + int64_t get_field_internal(const Ioss::StructuredBlock *sb, const Ioss::Field &field, + void *data, size_t data_size) const override; + + int64_t get_zc_field_internal(const Ioss::Region *reg, const Ioss::Field &field, void **data, + size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, void **data, + size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::EdgeBlock *eb, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::FaceBlock *fb, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::ElementBlock *eb, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::SideBlock *sb, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::NodeSet *ns, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::EdgeSet *es, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::FaceSet *fs, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::ElementSet *es, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::SideSet *ss, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::CommSet *cs, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::Assembly *as, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::Blob *bl, const Ioss::Field &field, + void **data, size_t *data_size) const override; + int64_t get_zc_field_internal(const Ioss::StructuredBlock *sb, const Ioss::Field &field, + void **data, size_t *data_size) const override; int64_t put_field_internal(const Ioss::Region *reg, const Ioss::Field &field, void *data, - size_t data_size) const override - { - return -1; - } + size_t data_size) const override; int64_t put_field_internal(const Ioss::NodeBlock *nb, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::EdgeBlock *nb, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::EdgeBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::FaceBlock *nb, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::FaceBlock *fb, const Ioss::Field &field, void *data, size_t data_size) const override; int64_t put_field_internal(const Ioss::ElementBlock *eb, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::SideBlock *fb, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::SideBlock *sb, const Ioss::Field &field, void *data, size_t data_size) const override; int64_t put_field_internal(const Ioss::NodeSet *ns, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::EdgeSet *ns, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::EdgeSet *es, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::FaceSet *ns, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::FaceSet *fs, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::ElementSet *ns, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::ElementSet *es, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::SideSet *fs, const Ioss::Field &field, void *data, + int64_t put_field_internal(const Ioss::SideSet *ss, const Ioss::Field &field, void *data, size_t data_size) const override; int64_t put_field_internal(const Ioss::CommSet *cs, const Ioss::Field &field, void *data, size_t data_size) const override; - int64_t put_field_internal(const Ioss::Assembly * /*as*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const override; - int64_t put_field_internal(const Ioss::Blob * /*bl*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const override; - int64_t put_field_internal(const Ioss::StructuredBlock * /*sb*/, const Ioss::Field & /*field*/, - void * /*data*/, size_t /*data_size*/) const override; + int64_t put_field_internal(const Ioss::Assembly *as, const Ioss::Field &field, void *data, + size_t data_size) const override; + int64_t put_field_internal(const Ioss::Blob *bl, const Ioss::Field &field, + void *data, size_t data_size) const override; + int64_t put_field_internal(const Ioss::StructuredBlock *sb, const Ioss::Field &field, + void *data, size_t data_size) const override; class ImplementationT; std::unique_ptr Impl; diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/CMakeLists.txt b/packages/seacas/libraries/ioss/src/catalyst_tests/CMakeLists.txt new file mode 100644 index 0000000000..123f70c850 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/CMakeLists.txt @@ -0,0 +1,351 @@ +TRIBITS_ADD_LIBRARY( + Iocatalyst_TestDriverMain +HEADERS + Iocatalyst_BlockMesh.h + Iocatalyst_BlockMeshSet.h + Iocatalyst_DatabaseIOTest.h +SOURCES + Iocatalyst_BlockMesh.C + Iocatalyst_BlockMeshSet.C + Iocatalyst_DatabaseIOTest.C + Iocatalyst_TestDriverMain.C +) + +TRIBITS_ADD_EXECUTABLE( + Iocatalyst_BlockMeshTest + SOURCES + Iocatalyst_BlockMeshTest.C +) + +TRIBITS_ADD_TEST( + Iocatalyst_BlockMeshTest + NAME Iocatalyst_BlockMeshTest + NUM_MPI_PROCS 1 +) + +TRIBITS_ADD_EXECUTABLE( + Iocatalyst_BlockMeshSetTest + SOURCES + Iocatalyst_BlockMeshSetTest.C +) + +TRIBITS_ADD_TEST( + Iocatalyst_BlockMeshSetTest + NAME Iocatalyst_BlockMeshSetTest + NUM_MPI_PROCS 1 +) + +TRIBITS_ADD_EXECUTABLE( + Iocatalyst_LoggingTest + SOURCES + Iocatalyst_LoggingTest.C +) + +TRIBITS_ADD_TEST( + Iocatalyst_LoggingTest + NAME Iocatalyst_LoggingTest + NUM_MPI_PROCS 1 +) + +TRIBITS_ADD_EXECUTABLE( + Iocatalyst_ManagerTest + SOURCES + Iocatalyst_ManagerTest.C +) + +TRIBITS_ADD_TEST( + Iocatalyst_ManagerTest + NAME Iocatalyst_ManagerTest + NUM_MPI_PROCS 1 +) + +TRIBITS_ADD_EXECUTABLE( + Iocatalyst_StructuredBlockTest + SOURCES + Iocatalyst_StructuredBlockTest.C +) + +TRIBITS_ADD_EXECUTABLE( + Iocatalyst_ElementBlockTest + SOURCES + Iocatalyst_ElementBlockTest.C +) + +SET(CATALYST_IOSS_ENTITY_TESTS + Iocatalyst_StructuredBlockTest + Iocatalyst_ElementBlockTest +) + +FOREACH(CATALYST_TEST ${CATALYST_IOSS_ENTITY_TESTS}) + FOREACH(MPI_RANKS 1 4) + TRIBITS_ADD_TEST( + ${CATALYST_TEST} + NAME ${CATALYST_TEST} + NUM_MPI_PROCS ${MPI_RANKS} + ) + ENDFOREACH() +ENDFOREACH() + +function(catalyst_test_ioshell_generated test_name + ioshell_gen_args + ioshell_output_file_name + test_time + test_time_step + num_procs) + +set(CATALYST_FNAME catalyst_time_${test_time_step}_np_${num_procs}_${ioshell_output_file_name}) +set(IOSHELL_FNAME ioshell_time_${test_time_step}_np_${num_procs}_${ioshell_output_file_name}) + +if(num_procs GREATER 1) + set(CATALYST_FNAME_EPU ${CATALYST_FNAME}.${num_procs}.0) +else() + set(CATALYST_FNAME_EPU ${CATALYST_FNAME}) +endif() + +TRIBITS_ADD_ADVANCED_TEST(${test_name} + TEST_0 EXEC io_shell ARGS --in_type generated ${ioshell_gen_args} + ${ioshell_output_file_name} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_1 EXEC decomp ARGS -p ${num_procs} ${ioshell_output_file_name} + DIRECTORY ../../../../scripts + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_2 EXEC io_shell ARGS -out_type catalyst ${ioshell_output_file_name} + ${test_time_step} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS ${num_procs} + TEST_3 EXEC io_shell ARGS -in_type catalyst ${test_time_step} + ${CATALYST_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS ${num_procs} + TEST_4 EXEC epu ARGS -auto ${CATALYST_FNAME_EPU} + DIRECTORY ../../../../applications/epu + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_5 EXEC io_shell ARGS -select_times ${test_time} + ${ioshell_output_file_name} ${IOSHELL_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_6 EXEC exodiff ARGS -pedantic ${IOSHELL_FNAME} + ${CATALYST_FNAME} + DIRECTORY ../../../../applications/exodiff + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + ENVIRONMENT CATALYST_DATA_DUMP_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/${test_name} + ) +endfunction() + +foreach(NUM_PROCS 1 4) + + catalyst_test_ioshell_generated( + "Iocatalyst_10x10x10_hex_MPI_${NUM_PROCS}" + "10x10x10+times:4+variables:element,2,nodal,3" + "ioshell_10x10x10.g" "3" "3" ${NUM_PROCS}) + + catalyst_test_ioshell_generated( + "Iocatalyst_10x10x10_tets_MPI_${NUM_PROCS}" + "10x10x10+tets:+times:2+variables:element,2,nodal,3" + "ioshell_10x10x10_tets.g" "1" "1" ${NUM_PROCS}) + + catalyst_test_ioshell_generated( + "Iocatalyst_10x10x10_pyramids_MPI_${NUM_PROCS}" + "10x10x10+pyramids:+times:2+variables:element,2,nodal,3" + "ioshell_10x10x10_pyramids.g" "1" "1" ${NUM_PROCS}) + + catalyst_test_ioshell_generated( + "Iocatalyst_10x10x10_shell_MPI_${NUM_PROCS}" + "10x10x10+shell:xX:+times:2+variables:element,2,nodal,3" + "ioshell_10x10x10_shell.g" "1" "1" ${NUM_PROCS}) + + catalyst_test_ioshell_generated( + "Iocatalyst_10x10x10_nodeset_MPI_${NUM_PROCS}" + "10x10x10+nodeset:xX:+times:2+variables:element,2,nodal,3,nodeset,4" + "ioshell_10x10x10_nodeset.g" "1" "1" ${NUM_PROCS}) + + catalyst_test_ioshell_generated( + "Iocatalyst_10x10x10_sideset_MPI_${NUM_PROCS}" + "10x10x10+sideset:xX:+times:2+variables:element,2,nodal,3,sideset,4" + "ioshell_10x10x10_sideset.g" "1" "1" ${NUM_PROCS}) + +endforeach() + +function(catalyst_test_ioshell_exodus_file test_name + input_file + test_time + test_time_step + num_procs) + +set(CATALYST_FNAME catalyst_time_${test_time_step}_np_${num_procs}_${input_file}) +set(IOSHELL_FNAME ioshell_time_${test_time_step}_np_${num_procs}_${input_file}) + +if(num_procs GREATER 1) + set(CATALYST_FNAME_EPU ${CATALYST_FNAME}.${num_procs}.0) +else() + set(CATALYST_FNAME_EPU ${CATALYST_FNAME}) +endif() + +TRIBITS_ADD_ADVANCED_TEST(${test_name} + TEST_0 EXEC decomp ARGS -p + ${num_procs} ${input_file} + DIRECTORY ../../../../scripts + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_1 EXEC io_shell ARGS -out_type catalyst + ${input_file} ${test_time_step} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS ${num_procs} + TEST_2 EXEC io_shell ARGS -in_type catalyst + ${test_time_step} ${CATALYST_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS ${num_procs} + TEST_3 EXEC epu ARGS -auto ${CATALYST_FNAME_EPU} + DIRECTORY ../../../../applications/epu + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_4 EXEC io_shell ARGS -select_times + ${test_time} ${input_file} ${IOSHELL_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_5 EXEC exodiff ARGS -pedantic + ${IOSHELL_FNAME} ${CATALYST_FNAME} + DIRECTORY ../../../../applications/exodiff + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + ENVIRONMENT CATALYST_DATA_DUMP_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/${test_name} +) +endfunction() + +set(EXO_TEST_FILES + cube.g + two-block.g + 8-block.g + can.ex2) + +foreach(fname ${EXO_TEST_FILES}) + configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../main/test/${fname} + ${fname} COPYONLY) +endforeach() + +foreach(NUM_PROCS 1 4) + catalyst_test_ioshell_exodus_file( + "Iocatalyst_cube_g_MPI_${NUM_PROCS}" + "cube.g" "1" "1" ${NUM_PROCS}) + catalyst_test_ioshell_exodus_file( + "Iocatalyst_two_block_g_MPI_${NUM_PROCS}" + "two-block.g" "1" "1" ${NUM_PROCS}) + catalyst_test_ioshell_exodus_file( + "Iocatalyst_eight_block_g_MPI_${NUM_PROCS}" + "8-block.g" "0.05" "5" ${NUM_PROCS}) + catalyst_test_ioshell_exodus_file( + "Iocatalyst_can_ex2_MPI_${NUM_PROCS}" + "can.ex2" "0.00219992" "22" ${NUM_PROCS}) +endforeach() + +if ( NETCDF_NCDUMP_BINARY ) + +function(catalyst_test_ioshell_generated_exodus_file test_name + gen_exo_file_command + gen_exo_file_args + gen_exo_file_name + test_time + test_time_step) + +set(CATALYST_FNAME catalyst_time_${test_time_step}_${gen_exo_file_name}) +set(IOSHELL_FNAME ioshell_time_${test_time_step}_${gen_exo_file_name}) +set(INPUT_FILE_PATH ${gen_exo_file_name}) + +TRIBITS_ADD_ADVANCED_TEST(${test_name} + TEST_0 EXEC ${gen_exo_file_command} ARGS ${gen_exo_file_args} + DIRECTORY ../../../exodus/test + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_1 EXEC io_shell ARGS -out_type catalyst ${INPUT_FILE_PATH} ${test_time_step} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_2 EXEC io_shell ARGS -in_type catalyst ${test_time_step} ${CATALYST_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_3 EXEC io_shell ARGS -select_times ${test_time} ${INPUT_FILE_PATH} ${IOSHELL_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_4 EXEC exodiff ARGS -pedantic ${IOSHELL_FNAME} ${CATALYST_FNAME} + DIRECTORY ../../../../applications/exodiff + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + ENVIRONMENT CATALYST_DATA_DUMP_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/${test_name} +) +endfunction() + +catalyst_test_ioshell_generated_exodus_file("Iocatalyst_test_blob_exo_MPI_1" + "testwt-blob" "" "test-blob.exo" "0.02" "1") + +catalyst_test_ioshell_generated_exodus_file("Iocatalyst_test_seacas_exodus_exoIIC_MPI_1" + "SEACASExodus_ExoIICTests.exe" "CreateEdgeFace" "edgeFace.exo" "1" "0") + +endif() + +IF (TPL_ENABLE_CGNS) + +if ( CGNS_CGNSDIFF_BINARY ) + # Do nothing. Set earlier in config process... +else() + find_program (CGNS_CGNSDIFF_BINARY + NAME cgnsdiff + PATHS + ${CGNS_BINARY_DIR} + ${CGNS_LIBRARY_DIRS}/../bin + $ENV{ACCESS}/bin + $ENV{CGNS_DIR}/bin + $ENV{CGNS_DIR}/cgnsdiff + ENV PATH + ${CGNS_DIR}/bin + ) +endif() + +if ( CGNS_CGNSDIFF_BINARY ) + +function(catalyst_test_ioshell_cgns_file test_name + input_file + test_time + test_time_step) + +set(CATALYST_FNAME catalyst_time_${test_time_step}_${input_file}) +set(IOSHELL_FNAME ioshell_time_${test_time_step}_${input_file}) +set(INPUT_FILE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../main/test/${input_file}) + +TRIBITS_ADD_ADVANCED_TEST(${test_name} + TEST_0 EXEC io_shell ARGS -debug -out_type catalyst ${INPUT_FILE_PATH} ${test_time_step} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_1 EXEC io_shell ARGS -in_type catalyst ${test_time_step} ${CATALYST_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_2 EXEC io_shell ARGS -select_times ${test_time} ${INPUT_FILE_PATH} ${IOSHELL_FNAME} + DIRECTORY ../main + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + TEST_3 EXEC ${CGNS_CGNSDIFF_BINARY} ARGS -d ${IOSHELL_FNAME} ${CATALYST_FNAME} + NOEXEPREFIX NOEXESUFFIX + NUM_MPI_PROCS 1 + ENVIRONMENT CATALYST_DATA_DUMP_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/${test_name} +) +endfunction() + +catalyst_test_ioshell_cgns_file( + "Iocatalyst_sparc1_cgns_MPI_1" "sparc1.cgns" "15.992" "1") + +endif() +endif() diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMesh.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMesh.C new file mode 100644 index 0000000000..745b9cf91f --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMesh.C @@ -0,0 +1,294 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include +#include + +namespace Iocatalyst { + + BlockMesh::ID BlockMesh::_id = 1; + + BlockMesh::BlockMesh() + { + partition.id = 0; + partition.size = 1; + extents.i = 1; + extents.j = 1; + extents.k = 1; + partitionExtents.i = 1; + partitionExtents.j = 1; + partitionExtents.k = 1; + partitionStart.i = 0; + partitionStart.j = 0; + partitionStart.k = 0; + id = _id++; + } + + BlockMesh::~BlockMesh() {} + + void BlockMesh::init(const Partition &part, const Extent &numBlocks, const Extent &origin) + { + if (part.id < 0 || part.size < 0 || part.id >= part.size) { + std::ostringstream errmsg; + errmsg << "Invalid partition: id = " << part.id << std::string(", size = ") << part.size + << "\n"; + IOSS_ERROR(errmsg); + } + this->partition = part; + this->extents = numBlocks; + this->origin = origin; + splitBlock(); + } + + void BlockMesh::splitBlock() + { + // Split algorithm from vtkExtentTranslator.cxx SplitExtent() + + unsigned long size[3]; + int numPiecesInFirstHalf; + int splitAxis; + long int mid; + int ext[6]; + int numPieces = getPartition().size; + int piece = getPartition().id; + fillExtents(ext); + setPartitionFromExtents(ext); + + while (numPieces > 1) { + size[0] = ext[1] - ext[0]; + size[1] = ext[3] - ext[2]; + size[2] = ext[5] - ext[4]; + + if (size[2] >= size[1] && size[2] >= size[0] && size[2] / 2 >= 1) { + splitAxis = 2; + } + else if (size[1] >= size[0] && size[1] / 2 >= 1) { + splitAxis = 1; + } + else if (size[0] / 2 >= 1) { + splitAxis = 0; + } + else { + splitAxis = -1; + } + + if (splitAxis == -1) { + if (piece == 0) { + numPieces = 1; + } + else { + setPartitionEmpty(); + return; + } + } + else { + numPiecesInFirstHalf = (numPieces / 2); + mid = size[splitAxis]; + mid = (mid * numPiecesInFirstHalf) / numPieces + ext[splitAxis * 2]; + if (piece < numPiecesInFirstHalf) { + ext[splitAxis * 2 + 1] = mid; + numPieces = numPiecesInFirstHalf; + } + else { + ext[splitAxis * 2] = mid; + numPieces = numPieces - numPiecesInFirstHalf; + piece -= numPiecesInFirstHalf; + } + } + } + setPartitionFromExtents(ext); + } + + void BlockMesh::fillExtents(int *ext) + { + if (getExtents().i == 0) { + ext[0] = 0; + ext[1] = -1; + } + else { + ext[0] = 0; + ext[1] = getExtents().i; + } + + if (getExtents().j == 0) { + ext[2] = 0; + ext[3] = -1; + } + else { + ext[2] = 0; + ext[3] = getExtents().j; + } + + if (getExtents().k == 0) { + ext[4] = 0; + ext[5] = -1; + } + else { + ext[4] = 0; + ext[5] = getExtents().k; + } + } + + void BlockMesh::setPartitionFromExtents(int ext[6]) + { + int sizeX = ext[1] - ext[0]; + int sizeY = ext[3] - ext[2]; + int sizeZ = ext[5] - ext[4]; + if (sizeX <= 0 || sizeY <= 0 || sizeZ <= 0) { + setPartitionEmpty(); + return; + } + + partitionExtents.i = sizeX; + partitionStart.i = ext[0]; + + partitionExtents.j = sizeY; + partitionStart.j = ext[2]; + + partitionExtents.k = sizeZ; + partitionStart.k = ext[4]; + } + + void BlockMesh::setPartitionEmpty() + { + partitionExtents.i = 0; + partitionExtents.j = 0; + partitionExtents.k = 0; + partitionStart.i = 0; + partitionStart.j = 0; + partitionStart.k = 0; + } + + bool BlockMesh::isPartitionEmpty() const + { + return partitionExtents.i == 0 || partitionExtents.j == 0 || partitionExtents.k == 0; + } + + BlockMesh::ID BlockMesh::getID() const { return id; } + + int BlockMesh::getNumPoints() const { return getNumInBlockMesh(POINT_OFFSET); } + + int BlockMesh::getNumPartitionPoints() const { return getNumInPartition(POINT_OFFSET); } + + BlockMesh::IDList BlockMesh::getPartitionPointIDs() const + { + return getPartitionIDs(POINT_OFFSET); + } + + BlockMesh::ID BlockMesh::getPointIDfromCoords(unsigned int i, unsigned int j, + unsigned int k) const + { + Extent coords = {i, j, k}; + Extent bounds = {extents.i + POINT_OFFSET, extents.j + POINT_OFFSET, extents.k + POINT_OFFSET}; + return getIDfromCoords(coords, bounds); + } + + BlockMesh::Point BlockMesh::getPointCoordsForPointID(ID pointID) const + { + Point p; + Extent bounds = {extents.i + POINT_OFFSET, extents.j + POINT_OFFSET, extents.k + POINT_OFFSET}; + Extent ext = getCoordsForID(pointID, bounds); + p.x = origin.i + ext.i * BLOCK_LENGTH; + p.y = origin.j + ext.j * BLOCK_LENGTH; + p.z = origin.k + ext.k * BLOCK_LENGTH; + return p; + } + + BlockMesh::ID BlockMesh::getGlobalIDForPointID(ID pointID) + { + Extent pointExt = getExtents(); + pointExt.i += 1; + pointExt.j += 1; + pointExt.k += 1; + auto coords = getCoordsForID(pointID, pointExt); + coords.i += origin.i; + coords.j += origin.j; + coords.k += origin.k; + return getIDfromCoords(coords, getGlobalPointExtents()); + } + + int BlockMesh::getNumBlocks() const { return getNumInBlockMesh(BLOCK_OFFSET); } + + int BlockMesh::getNumPartitionBlocks() const { return getNumInPartition(BLOCK_OFFSET); } + + BlockMesh::IDList BlockMesh::getPartitionBlockIDs() const + { + return getPartitionIDs(BLOCK_OFFSET); + } + + BlockMesh::BlockConn BlockMesh::getBlockConnectivityPointIDs(ID blockID) const + { + BlockConn conn; + Extent bounds = {extents.i + BLOCK_OFFSET, extents.j + BLOCK_OFFSET, extents.k + BLOCK_OFFSET}; + Extent e = getCoordsForID(blockID, bounds); + conn[0] = getPointIDfromCoords(e.i, e.j, e.k); + conn[1] = getPointIDfromCoords(e.i + 1, e.j, e.k); + conn[2] = getPointIDfromCoords(e.i + 1, e.j + 1, e.k); + conn[3] = getPointIDfromCoords(e.i, e.j + 1, e.k); + conn[4] = getPointIDfromCoords(e.i, e.j, e.k + 1); + conn[5] = getPointIDfromCoords(e.i + 1, e.j, e.k + 1); + conn[6] = getPointIDfromCoords(e.i + 1, e.j + 1, e.k + 1); + conn[7] = getPointIDfromCoords(e.i, e.j + 1, e.k + 1); + return conn; + } + + BlockMesh::ID BlockMesh::getGlobalIDForBlockID(ID blockID) + { + auto coords = getCoordsForID(blockID, getExtents()); + coords.i += origin.i; + coords.j += origin.j; + coords.k += origin.k; + return getIDfromCoords(coords, getGlobalBlockExtents()); + } + + BlockMesh::IDList BlockMesh::getPartitionIDs(unsigned int offset) const + { + BlockMesh::IDList ids; + Extent bounds = {extents.i + offset, extents.j + offset, extents.k + offset}; + if (!isPartitionEmpty()) { + for (unsigned int k = partitionStart.k; k < partitionStart.k + partitionExtents.k + offset; + k++) { + for (unsigned int j = partitionStart.j; j < partitionStart.j + partitionExtents.j + offset; + j++) { + for (unsigned int i = partitionStart.i; + i < partitionStart.i + partitionExtents.i + offset; i++) { + Extent coords = {i, j, k}; + ids.push_back(getIDfromCoords(coords, bounds)); + } + } + } + } + return ids; + } + + BlockMesh::ID BlockMesh::getIDfromCoords(Extent coords, Extent bounds) + { + return coords.k * bounds.i * bounds.j + coords.j * bounds.i + coords.i + 1; + } + + BlockMesh::Extent BlockMesh::getCoordsForID(ID id, Extent bounds) + { + Extent ext; + int zeroBasedID = id - 1; + unsigned int sizeXY = bounds.i * bounds.j; + ext.k = zeroBasedID / sizeXY; + ext.j = (zeroBasedID - ext.k * sizeXY) / bounds.i; + ext.i = zeroBasedID - ext.k * sizeXY - ext.j * bounds.i; + return ext; + } + + int BlockMesh::getNumInPartition(unsigned int offset) const + { + return (partitionExtents.i + offset) * (partitionExtents.j + offset) * + (partitionExtents.k + offset); + } + + int BlockMesh::getNumInBlockMesh(unsigned int offset) const + { + return (extents.i + offset) * (extents.j + offset) * (extents.k + offset); + } + +} // namespace Iocatalyst diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMesh.h b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMesh.h new file mode 100644 index 0000000000..2732c6d60e --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMesh.h @@ -0,0 +1,103 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#pragma once + +#include "iocatalyst_export.h" +#include +#include + +namespace Iocatalyst { + + class IOCATALYST_EXPORT BlockMesh + { + public: + struct Partition + { + int id; + int size; + }; + + struct Point + { + double x; + double y; + double z; + }; + + struct Extent + { + unsigned int i; + unsigned int j; + unsigned int k; + }; + + using BlockConn = std::array; + using IDList = std::vector; + using ID = unsigned int; + static const unsigned int BLOCK_OFFSET = 0; + static const unsigned int POINT_OFFSET = 1; + static constexpr double BLOCK_LENGTH = 1.0; + + static const unsigned int I_GLOBAL = 1000; + static const unsigned int J_GLOBAL = 1000; + static const unsigned int K_GLOBAL = 1000; + + BlockMesh(); + ~BlockMesh(); + + void init(const Partition &part, const Extent &numBlocks, const Extent &origin); + + const Partition &getPartition() const { return partition; } + + const Extent &getOrigin() const { return origin; } + + const Extent &getExtents() const { return extents; } + + const Extent &getPartitionExtents() const { return partitionExtents; } + const Extent &getPartitionStart() const { return partitionStart; } + + ID getID() const; + + bool isPartitionEmpty() const; + + int getNumBlocks() const; + int getNumPartitionBlocks() const; + IDList getPartitionBlockIDs() const; + BlockConn getBlockConnectivityPointIDs(ID blockID) const; + static Extent getGlobalBlockExtents() { return {I_GLOBAL, J_GLOBAL, K_GLOBAL}; }; + ID getGlobalIDForBlockID(ID blockID); + + int getNumPoints() const; + int getNumPartitionPoints() const; + IDList getPartitionPointIDs() const; + ID getPointIDfromCoords(unsigned int i, unsigned int j, unsigned int k) const; + Point getPointCoordsForPointID(ID pointID) const; + static Extent getGlobalPointExtents() { return {I_GLOBAL + 1, J_GLOBAL + 1, K_GLOBAL + 1}; }; + ID getGlobalIDForPointID(ID pointID); + + static Extent getCoordsForID(ID id, Extent bounds); + static ID getIDfromCoords(Extent coords, Extent bounds); + + private: + Partition partition; + Extent origin; + Extent extents; + Extent partitionExtents; + Extent partitionStart; + Extent globalBlockExtents; + void splitBlock(); + void fillExtents(int *ext); + void setPartitionFromExtents(int ext[6]); + void setPartitionEmpty(); + IDList getPartitionIDs(unsigned int offset) const; + int getNumInPartition(unsigned int offset) const; + int getNumInBlockMesh(unsigned int offset) const; + ID id; + static ID _id; + }; + +} // namespace Iocatalyst diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSet.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSet.C new file mode 100644 index 0000000000..a94edd44af --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSet.C @@ -0,0 +1,374 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Iocatalyst { + + void BlockMeshSet::addBlockMesh(const BlockMesh &blockMesh) { bms.push_back(blockMesh); } + + int BlockMeshSet::getNumLocalPointsInMeshSet() + { + std::unordered_set pids; + for (auto bm : bms) { + BlockMesh::IDList ids = bm.getPartitionPointIDs(); + for (auto id : ids) { + auto gid = bm.getGlobalIDForPointID(id); + if (pids.find(gid) == pids.end()) { + pids.insert(gid); + } + } + } + return pids.size(); + } + + void BlockMeshSet::writeCatalystIOSSFile(IOSSparams &iop) + { + CatalystManager::getInstance().reset(); + iop.isCatalyst = true; + writeIOSSFile(iop); + Ioss::PropertyManager cdbProps; + cdbProps.add(Ioss::Property("CATALYST_CONDUIT_NODE", iop.getCatalystConduitNode())); + + Ioss::DatabaseIO *cdbi = + Ioss::IOFactory::create(CATALYST_DATABASE_TYPE, CATALYST_DUMMY_DATABASE, Ioss::READ_RESTART, + Ioss::ParallelUtils::comm_world(), cdbProps); + if (cdbi == nullptr || !cdbi->ok(true)) { + return; + } + + Ioss::PropertyManager properties; + Ioss::DatabaseIO *cdbo = Ioss::IOFactory::create(iop.dbType, iop.fileName, Ioss::WRITE_RESULTS, + Ioss::ParallelUtils::comm_world(), properties); + + if (cdbo == nullptr || !cdbo->ok(true)) { + std::ostringstream errmsg; + errmsg << "Unable to open IOSS database " + iop.fileName + "\n"; + IOSS_ERROR(errmsg); + } + + Ioss::Region cor(cdbo); + Ioss::Region cir(cdbi); + Ioss::MeshCopyOptions options; + options.data_storage_type = 1; + Ioss::copy_database(cir, cor, options); + } + + void BlockMeshSet::writeIOSSFile(IOSSparams &iop) + { + openIOSSDatabase(iop); + switchStateDefineModel(iop); + switchStateModel(iop); + switchStateDefineTransient(iop); + switchStateTransient(iop); + closeIOSSDatabase(iop); + } + + void BlockMeshSet::openIOSSDatabase(IOSSparams &iop) + { + Ioss::PropertyManager properties; + std::string dbType = iop.dbType; + if (iop.isCatalyst) { + dbType = CATALYST_DATABASE_TYPE; + } + iop.databaseIO = Ioss::IOFactory::create(dbType, iop.fileName, Ioss::WRITE_RESULTS, + Ioss::ParallelUtils::comm_world(), properties); + + if (iop.databaseIO == nullptr || !iop.databaseIO->ok(true)) { + std::ostringstream errmsg; + errmsg << "Unable to open IOSS database " + iop.fileName + "\n"; + IOSS_ERROR(errmsg); + } + iop.region = std::unique_ptr(new Ioss::Region(iop.databaseIO)); + } + + void BlockMeshSet::closeIOSSDatabase(IOSSparams &iop) + { + iop.region.reset(); + iop.databaseIO = nullptr; + } + + void BlockMeshSet::switchStateDefineModel(IOSSparams &iop) + { + iop.region->begin_mode(Ioss::STATE_DEFINE_MODEL); + if (iop.isStructured()) { + writeStructuredBlockDefinitions(iop); + } + else { + writeUnstructuredBlockDefinitions(iop); + } + iop.region->end_mode(Ioss::STATE_DEFINE_MODEL); + } + + void BlockMeshSet::switchStateModel(IOSSparams &iop) + { + iop.region->begin_mode(Ioss::STATE_MODEL); + if (iop.isStructured()) { + writeStructuredBlockBulkData(iop); + } + else { + writeUnstructuredBlockBulkData(iop); + } + if (iop.isCatalyst) { + saveConduitNode(iop); + } + iop.region->end_mode(Ioss::STATE_MODEL); + } + + void BlockMeshSet::switchStateDefineTransient(IOSSparams &iop) + { + iop.region->begin_mode(Ioss::STATE_DEFINE_TRANSIENT); + if (iop.isStructured()) { + writeStructuredTransientFieldDefinitions(iop); + } + else { + writeUnstructuredTransientFieldDefinitions(iop); + } + iop.region->end_mode(Ioss::STATE_DEFINE_TRANSIENT); + } + void BlockMeshSet::switchStateTransient(IOSSparams &iop) + { + iop.region->begin_mode(Ioss::STATE_TRANSIENT); + int tstep = iop.region->add_state(0.0); + iop.region->begin_state(tstep); + if (iop.isStructured()) { + writeStructuredTransientBulkData(iop); + } + else { + writeUnstructuredTransientBulkData(iop); + } + iop.region->end_state(tstep); + if (iop.isCatalyst) { + saveConduitNode(iop); + } + iop.region->end_mode(Ioss::STATE_TRANSIENT); + } + + void BlockMeshSet::saveConduitNode(IOSSparams &iop) + { + auto c_node = reinterpret_cast( + ((Iocatalyst::DatabaseIO *)iop.databaseIO)->get_catalyst_conduit_node()); + conduit_node_set_node(conduit_cpp::c_node(&iop.conduitNode), c_node); + } + + void BlockMeshSet::writeStructuredBlockDefinitions(IOSSparams &iop) + { + int spatialDims = 3; + for (auto bm : bms) { + Ioss::IJK_t parentOffsets = {{(int)bm.getPartitionStart().i, (int)bm.getPartitionStart().j, + (int)bm.getPartitionStart().k}}; + Ioss::IJK_t globalSizes = { + {(int)bm.getExtents().i, (int)bm.getExtents().j, (int)bm.getExtents().k}}; + Ioss::IJK_t localSizes = {{(int)bm.getPartitionExtents().i, (int)bm.getPartitionExtents().j, + (int)bm.getPartitionExtents().k}}; + Ioss::StructuredBlock *iossBlock = + new Ioss::StructuredBlock(iop.databaseIO, getStructuredBlockName(bm.getID()), spatialDims, + localSizes, parentOffsets, globalSizes); + int node_count = (bm.getPartitionExtents().i + 1) * (bm.getPartitionExtents().j + 1) * + (bm.getPartitionExtents().k + 1); + Ioss::NodeBlock *nodeBlock = new Ioss::NodeBlock( + iop.databaseIO, getStructuredNodeBlockName(bm.getID()), node_count, spatialDims); + iop.region->add(iossBlock); + iop.region->add(nodeBlock); + } + } + + void BlockMeshSet::writeStructuredBlockBulkData(IOSSparams &iop) + { + std::vector coordx; + std::vector coordy; + std::vector coordz; + BlockMesh::Point origin; + origin.x = 0.0; + origin.y = 0.0; + origin.z = 0.0; + for (auto bm : bms) { + const int numI = bm.getPartitionExtents().i + 1; + const int numJ = bm.getPartitionExtents().j + 1; + const int numK = bm.getPartitionExtents().k + 1; + const int numPoints = numI * numJ * numK; + + coordx.resize(numPoints); + coordy.resize(numPoints); + coordz.resize(numPoints); + + for (int k = 0; k < numK; ++k) { + const int kOffset = k * numI * numJ; + for (int j = 0; j < numJ; ++j) { + const int kjOffset = kOffset + j * numI; + for (int i = 0; i < numI; ++i) { + coordx[kjOffset + i] = + i * bm.BLOCK_LENGTH + bm.getOrigin().i + bm.getPartitionStart().i; + coordy[kjOffset + i] = + j * bm.BLOCK_LENGTH + bm.getOrigin().j + bm.getPartitionStart().j; + coordz[kjOffset + i] = + k * bm.BLOCK_LENGTH + bm.getOrigin().k + bm.getPartitionStart().k; + } + } + } + + auto iossBlock = iop.region->get_structured_block(getStructuredBlockName(bm.getID())); + iossBlock->put_field_data("mesh_model_coordinates_x", coordx); + iossBlock->put_field_data("mesh_model_coordinates_y", coordy); + iossBlock->put_field_data("mesh_model_coordinates_z", coordz); + } + } + + void BlockMeshSet::writeStructuredTransientFieldDefinitions(IOSSparams &iop) + { + for (auto bm : bms) { + auto iossBlock = iop.region->get_structured_block(getStructuredBlockName(bm.getID())); + iossBlock->field_add(Ioss::Field(IOSS_CELL_FIELD, Ioss::Field::REAL, IOSS_SCALAR_STORAGE, + Ioss::Field::TRANSIENT)); + iossBlock->get_node_block().field_add(Ioss::Field( + IOSS_POINT_FIELD, Ioss::Field::REAL, IOSS_SCALAR_STORAGE, Ioss::Field::TRANSIENT)); + } + } + + void BlockMeshSet::writeStructuredTransientBulkData(IOSSparams &iop) + { + + std::vector values; + for (auto bm : bms) { + values.clear(); + auto iossBlock = iop.region->get_structured_block(getStructuredBlockName(bm.getID())); + for (int j = 0; j < iossBlock->get_field(IOSS_CELL_FIELD).raw_count(); j++) { + values.push_back(bm.getPartition().id); + } + iossBlock->put_field_data(IOSS_CELL_FIELD, values); + + values.clear(); + for (int j = 0; j < iossBlock->get_node_block().get_field(IOSS_POINT_FIELD).raw_count(); + j++) { + values.push_back(bm.getPartition().id); + } + iossBlock->get_node_block().put_field_data(IOSS_POINT_FIELD, values); + } + } + + void BlockMeshSet::writeUnstructuredBlockDefinitions(IOSSparams &iop) + { + int spatialDims = 3; + Ioss::NodeBlock *nodeBlock = + new Ioss::NodeBlock(iop.databaseIO, "nodeblock", getNumLocalPointsInMeshSet(), spatialDims); + iop.region->add(nodeBlock); + for (auto bm : bms) { + Ioss::ElementBlock *elemBlock = new Ioss::ElementBlock( + iop.databaseIO, getUnstructuredBlockName(bm.getID()), "hex8", bm.getNumPartitionBlocks()); + iop.region->add(elemBlock); + } + } + + void BlockMeshSet::writeUnstructuredBlockBulkData(IOSSparams &iop) + { + Ioss::NodeBlock *nodeBlock = iop.region->get_node_block("nodeblock"); + std::vector coordx; + std::vector coordy; + std::vector coordz; + BlockMesh::IDList globalPointIds; + std::unordered_set pids; + for (auto bm : bms) { + BlockMesh::IDList ids = bm.getPartitionPointIDs(); + for (auto id : ids) { + auto gid = bm.getGlobalIDForPointID(id); + if (pids.find(gid) == pids.end()) { + BlockMesh::Point point = bm.getPointCoordsForPointID(id); + coordx.push_back(point.x); + coordy.push_back(point.y); + coordz.push_back(point.z); + globalPointIds.push_back(gid); + pids.insert(gid); + } + } + } + nodeBlock->put_field_data("mesh_model_coordinates_x", coordx); + nodeBlock->put_field_data("mesh_model_coordinates_y", coordy); + nodeBlock->put_field_data("mesh_model_coordinates_z", coordz); + nodeBlock->put_field_data("ids", globalPointIds); + + for (auto bm : bms) { + Ioss::ElementBlock *elemBlock = + iop.region->get_element_block(getUnstructuredBlockName(bm.getID())); + + std::vector connectivity(8 * bm.getNumPartitionBlocks()); + BlockMesh::IDList globalElemIds; + BlockMesh::IDList ids = bm.getPartitionBlockIDs(); + + for (int i = 0; i < ids.size(); i++) { + BlockMesh::BlockConn conn = bm.getBlockConnectivityPointIDs(ids[i]); + globalElemIds.push_back(bm.getGlobalIDForBlockID(ids[i])); + for (int j = 0; j < conn.size(); j++) { + connectivity[(i * 8) + j] = bm.getGlobalIDForPointID(conn[j]); + } + } + elemBlock->put_field_data("connectivity", connectivity); + elemBlock->put_field_data("ids", globalElemIds); + } + } + + void BlockMeshSet::writeUnstructuredTransientFieldDefinitions(IOSSparams &iop) + { + iop.region->field_add(Ioss::Field(IOSS_GLOBAL_FIELD, Ioss::Field::REAL, IOSS_SCALAR_STORAGE, + Ioss::Field::TRANSIENT)); + for (auto bm : bms) { + auto elemBlock = iop.region->get_element_block(getUnstructuredBlockName(bm.getID())); + elemBlock->field_add(Ioss::Field(IOSS_CELL_FIELD, Ioss::Field::REAL, IOSS_SCALAR_STORAGE, + Ioss::Field::TRANSIENT)); + auto nodeBlock = iop.region->get_node_block("nodeblock"); + nodeBlock->field_add(Ioss::Field(IOSS_POINT_FIELD, Ioss::Field::REAL, IOSS_SCALAR_STORAGE, + Ioss::Field::TRANSIENT)); + } + } + + void BlockMeshSet::writeUnstructuredTransientBulkData(IOSSparams &iop) + { + std::vector values; + values.push_back(3.14); + iop.region->put_field_data(IOSS_GLOBAL_FIELD, values); + for (auto bm : bms) { + values.clear(); + auto elemBlock = iop.region->get_element_block(getUnstructuredBlockName(bm.getID())); + for (int j = 0; j < elemBlock->get_field(IOSS_CELL_FIELD).raw_count(); j++) { + values.push_back(bm.getPartition().id); + } + elemBlock->put_field_data(IOSS_CELL_FIELD, values); + + auto nodeBlock = iop.region->get_node_block("nodeblock"); + values.clear(); + for (int j = 0; j < nodeBlock->get_field(IOSS_POINT_FIELD).raw_count(); j++) { + values.push_back(bm.getPartition().id); + } + nodeBlock->put_field_data(IOSS_POINT_FIELD, values); + } + } + + std::string BlockMeshSet::getStructuredBlockName(int index) + { + return "StructuredBlock" + std::to_string(index); + } + + std::string BlockMeshSet::getStructuredNodeBlockName(int index) + { + return "StructuredNodeBlock" + std::to_string(index); + } + + std::string BlockMeshSet::getUnstructuredBlockName(int index) + { + return "UnstructuredBlock" + std::to_string(index); + } + +} // namespace Iocatalyst diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSet.h b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSet.h new file mode 100644 index 0000000000..3041e92158 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSet.h @@ -0,0 +1,88 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#pragma once + +#include "iocatalyst_export.h" + +#include +#include +#include +#include +#include + +namespace Iocatalyst { + + class IOCATALYST_EXPORT BlockMeshSet + { + + public: + inline static const std::string CATALYST_DATABASE_TYPE = "catalyst"; + inline static const std::string CATALYST_DUMMY_DATABASE = "dummy.db"; + + class IOSSparams + { + public: + IOSSparams(const std::string &fileName, const std::string &dbType) + : fileName(fileName), dbType(dbType), databaseIO(nullptr), isCatalyst(false) + { + } + bool isStructured() { return dbType == CGNS_DATABASE_TYPE; } + void printCatalystConduitNode() { conduitNode.print_detailed(); } + void *getCatalystConduitNode() { return conduit_cpp::c_node(&conduitNode); } + std::string fileName; + std::string dbType; + Ioss::DatabaseIO *databaseIO; + bool isCatalyst; + std::unique_ptr region; + conduit_cpp::Node conduitNode; + + private: + IOSSparams(); + }; + + void addBlockMesh(const BlockMesh &blockMesh); + void writeIOSSFile(IOSSparams &iop); + void writeCatalystIOSSFile(IOSSparams &iop); + int getNumLocalPointsInMeshSet(); + + private: + std::vector bms; + + void openIOSSDatabase(IOSSparams &iop); + void closeIOSSDatabase(IOSSparams &iop); + + void switchStateDefineModel(IOSSparams &iop); + void switchStateModel(IOSSparams &iop); + void switchStateDefineTransient(IOSSparams &iop); + void switchStateTransient(IOSSparams &iop); + + void writeStructuredBlockDefinitions(IOSSparams &iop); + void writeStructuredBlockBulkData(IOSSparams &iop); + void writeStructuredTransientFieldDefinitions(IOSSparams &iop); + void writeStructuredTransientBulkData(IOSSparams &iop); + + void writeUnstructuredBlockDefinitions(IOSSparams &iop); + void writeUnstructuredBlockBulkData(IOSSparams &iop); + void writeUnstructuredTransientFieldDefinitions(IOSSparams &iop); + void writeUnstructuredTransientBulkData(IOSSparams &iop); + + void saveConduitNode(IOSSparams &iop); + + std::string getStructuredBlockName(int index); + std::string getStructuredNodeBlockName(int index); + + std::string getUnstructuredBlockName(int index); + + inline static const std::string CGNS_DATABASE_TYPE = "cgns"; + inline static const std::string EXODUS_DATABASE_TYPE = "exodus"; + inline static const std::string IOSS_CELL_FIELD = "cell"; + inline static const std::string IOSS_POINT_FIELD = "point"; + inline static const std::string IOSS_GLOBAL_FIELD = "global"; + inline static const std::string IOSS_SCALAR_STORAGE = "scalar"; + }; + +} // namespace Iocatalyst diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSetTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSetTest.C new file mode 100644 index 0000000000..b5a0094539 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshSetTest.C @@ -0,0 +1,34 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include + +TEST_F(Iocatalyst_DatabaseIOTest, GetNumLocalPointsInMeshSet) +{ + EXPECT_EQ(bmSet.getNumLocalPointsInMeshSet(), 0); + Iocatalyst::BlockMesh bmOne; + setBlockMeshSize(2, 2, 2); + addBlockMesh(bmOne); + EXPECT_EQ(bmSet.getNumLocalPointsInMeshSet(), 27); + + Iocatalyst::BlockMesh bmTwo; + setBlockMeshSize(1, 1, 1); + setOrigin(2, 0, 0); + addBlockMesh(bmTwo); + EXPECT_EQ(bmSet.getNumLocalPointsInMeshSet(), 31); + + Iocatalyst::BlockMesh bmThree; + setBlockMeshSize(2, 2, 2); + setOrigin(3, 0, 0); + addBlockMesh(bmThree); + EXPECT_EQ(bmSet.getNumLocalPointsInMeshSet(), 54); + + Iocatalyst::BlockMesh bmFour; + setBlockMeshSize(8, 3, 3); + setOrigin(5, 0, 0); + addBlockMesh(bmFour); + EXPECT_EQ(bmSet.getNumLocalPointsInMeshSet(), 189); +} \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshTest.C new file mode 100644 index 0000000000..1f9d43dfa0 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_BlockMeshTest.C @@ -0,0 +1,506 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include "gtest/gtest.h" +#include + +class BlockMeshTest : public ::testing::Test +{ +protected: + Iocatalyst::BlockMesh bmOne; + Iocatalyst::BlockMesh bmTwo; + Iocatalyst::BlockMesh bmThree; + Iocatalyst::BlockMesh bmFour; + Iocatalyst::BlockMesh::Partition part; + Iocatalyst::BlockMesh::Extent numBlocks; + Iocatalyst::BlockMesh::Extent origin; + + BlockMeshTest() + { + origin.i = 0; + origin.j = 0; + origin.k = 0; + } + + void checkLocalNumBlocks(const Iocatalyst::BlockMesh &bm, int i, int j, int k) + { + EXPECT_EQ(bm.getPartitionExtents().i, i); + EXPECT_EQ(bm.getPartitionExtents().j, j); + EXPECT_EQ(bm.getPartitionExtents().k, k); + } + + void checkLocalBlockStart(const Iocatalyst::BlockMesh &bm, int i, int j, int k) + { + EXPECT_EQ(bm.getPartitionStart().i, i); + EXPECT_EQ(bm.getPartitionStart().j, j); + EXPECT_EQ(bm.getPartitionStart().k, k); + } +}; + +TEST_F(BlockMeshTest, GetID) +{ + EXPECT_EQ(bmOne.getID(), 1); + EXPECT_EQ(bmTwo.getID(), 2); + EXPECT_EQ(bmThree.getID(), 3); + EXPECT_EQ(bmFour.getID(), 4); + Iocatalyst::BlockMesh bm = bmOne; + EXPECT_EQ(bm.getID(), 1); +} + +TEST_F(BlockMeshTest, Defaults) +{ + + EXPECT_EQ(bmOne.getPartition().id, 0); + EXPECT_EQ(bmOne.getPartition().size, 1); + + EXPECT_EQ(bmOne.getExtents().i, 1); + EXPECT_EQ(bmOne.getExtents().j, 1); + EXPECT_EQ(bmOne.getExtents().k, 1); + + EXPECT_EQ(bmOne.getPartitionExtents().i, 1); + EXPECT_EQ(bmOne.getPartitionExtents().j, 1); + EXPECT_EQ(bmOne.getPartitionExtents().k, 1); + + EXPECT_EQ(bmOne.getPartitionStart().i, 0); + EXPECT_EQ(bmOne.getPartitionStart().j, 0); + EXPECT_EQ(bmOne.getPartitionStart().k, 0); + + EXPECT_FALSE(bmOne.isPartitionEmpty()); +} + +TEST_F(BlockMeshTest, InitPartitionSizeOne) +{ + + numBlocks.i = 12; + numBlocks.j = 45; + numBlocks.k = 176; + part.id = 0; + part.size = 1; + + bmOne.init(part, numBlocks, origin); + EXPECT_EQ(bmOne.getPartition().id, 0); + EXPECT_EQ(bmOne.getPartition().size, 1); + EXPECT_EQ(bmOne.getExtents().i, 12); + EXPECT_EQ(bmOne.getExtents().j, 45); + EXPECT_EQ(bmOne.getExtents().k, 176); + checkLocalNumBlocks(bmOne, 12, 45, 176); + checkLocalBlockStart(bmOne, 0, 0, 0); +} + +TEST_F(BlockMeshTest, InitPartitionSizeTwoSmallestGrid) +{ + + part.id = 0; + part.size = 2; + numBlocks.i = 1; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + checkLocalNumBlocks(bmOne, 1, 1, 1); + checkLocalBlockStart(bmOne, 0, 0, 0); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + EXPECT_TRUE(bmTwo.isPartitionEmpty()); +} + +TEST_F(BlockMeshTest, InitPartitionSizeTwoEvenExtents) +{ + + part.id = 0; + part.size = 2; + numBlocks.i = 12; + numBlocks.j = 6; + numBlocks.k = 24; + bmOne.init(part, numBlocks, origin); + checkLocalNumBlocks(bmOne, 12, 6, 12); + checkLocalBlockStart(bmOne, 0, 0, 0); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + checkLocalNumBlocks(bmTwo, 12, 6, 12); + checkLocalBlockStart(bmTwo, 0, 0, 12); +} + +TEST_F(BlockMeshTest, InitPartitionSizeTwoOddExtents) +{ + + part.id = 0; + part.size = 2; + numBlocks.i = 12; + numBlocks.j = 6; + numBlocks.k = 27; + bmOne.init(part, numBlocks, origin); + checkLocalNumBlocks(bmOne, 12, 6, 13); + checkLocalBlockStart(bmOne, 0, 0, 0); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + checkLocalNumBlocks(bmTwo, 12, 6, 14); + checkLocalBlockStart(bmTwo, 0, 0, 13); +} + +TEST_F(BlockMeshTest, InitPartitionSizeTwoZandYnumBlocksOne) +{ + part.id = 0; + part.size = 2; + numBlocks.i = 13; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + checkLocalNumBlocks(bmOne, 6, 1, 1); + checkLocalBlockStart(bmOne, 0, 0, 0); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + checkLocalNumBlocks(bmTwo, 7, 1, 1); + checkLocalBlockStart(bmTwo, 6, 0, 0); +} + +TEST_F(BlockMeshTest, InitPartitionSizeThree) +{ + part.id = 0; + part.size = 3; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + EXPECT_TRUE(bmOne.isPartitionEmpty()); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + checkLocalNumBlocks(bmTwo, 2, 1, 1); + checkLocalBlockStart(bmTwo, 0, 0, 0); + part.id = 2; + bmThree.init(part, numBlocks, origin); + checkLocalNumBlocks(bmThree, 2, 1, 1); + checkLocalBlockStart(bmThree, 0, 1, 0); +} + +TEST_F(BlockMeshTest, GetPartitionPointIDsSizeOneOneBlock) +{ + std::vector points = {1, 2, 3, 4, 5, 6, 7, 8}; + EXPECT_EQ(bmOne.getPartitionPointIDs(), points); +} + +TEST_F(BlockMeshTest, GetPartitionPointIDsSizeOneTwoBlocksInX) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + std::vector points = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; + EXPECT_EQ(bmOne.getPartitionPointIDs(), points); +} + +TEST_F(BlockMeshTest, GetPartitionPointIDsSizeTwoOneBlock) +{ + + part.id = 0; + part.size = 2; + numBlocks.i = 1; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + std::vector points = {1, 2, 3, 4, 5, 6, 7, 8}; + EXPECT_EQ(bmOne.getPartitionPointIDs(), points); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + points.clear(); + EXPECT_EQ(bmTwo.getPartitionPointIDs(), points); +} + +TEST_F(BlockMeshTest, GetPartitionPointIDsSizeTwoTwoBlocksInY) +{ + part.id = 0; + part.size = 2; + numBlocks.i = 1; + numBlocks.j = 2; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + std::vector points = {1, 2, 3, 4, 7, 8, 9, 10}; + EXPECT_EQ(bmOne.getPartitionPointIDs(), points); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + std::vector pointsTwo = {3, 4, 5, 6, 9, 10, 11, 12}; + EXPECT_EQ(bmTwo.getPartitionPointIDs(), pointsTwo); +} + +TEST_F(BlockMeshTest, GetPartitionPointIDsSizeFourEightBlocks) +{ + part.id = 0; + part.size = 4; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + std::vector points = {1, 2, 3, 4, 5, 6, 10, 11, 12, 13, 14, 15}; + EXPECT_EQ(bmOne.getPartitionPointIDs(), points); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + std::vector pointsTwo = {4, 5, 6, 7, 8, 9, 13, 14, 15, 16, 17, 18}; + EXPECT_EQ(bmTwo.getPartitionPointIDs(), pointsTwo); + part.id = 2; + bmThree.init(part, numBlocks, origin); + std::vector pointsThree = {10, 11, 12, 13, 14, 15, 19, 20, 21, 22, 23, 24}; + EXPECT_EQ(bmThree.getPartitionPointIDs(), pointsThree); + part.id = 3; + bmFour.init(part, numBlocks, origin); + std::vector pointsFour = {13, 14, 15, 16, 17, 18, 22, 23, 24, 25, 26, 27}; + EXPECT_EQ(bmFour.getPartitionPointIDs(), pointsFour); +} + +TEST_F(BlockMeshTest, GetPointCoordsForGlobalIDSizeOneOneBlock) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 1; + numBlocks.j = 1; + numBlocks.k = 1; + origin = {0, 0, 0}; + bmOne.init(part, numBlocks, origin); + Iocatalyst::BlockMesh::Point p = bmOne.getPointCoordsForPointID(8); + EXPECT_DOUBLE_EQ(p.x, 1.0); + EXPECT_DOUBLE_EQ(p.y, 1.0); + EXPECT_DOUBLE_EQ(p.z, 1.0); +} + +TEST_F(BlockMeshTest, GetPointCoordsForGlobalIDSizeOneEightBlocks) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + origin = {2, 2, 2}; + bmOne.init(part, numBlocks, origin); + Iocatalyst::BlockMesh::Point p = bmOne.getPointCoordsForPointID(27); + EXPECT_DOUBLE_EQ(p.x, 4.0); + EXPECT_DOUBLE_EQ(p.y, 4.0); + EXPECT_DOUBLE_EQ(p.z, 4.0); + p = bmOne.getPointCoordsForPointID(1); + EXPECT_DOUBLE_EQ(p.x, 2.0); + EXPECT_DOUBLE_EQ(p.y, 2.0); + EXPECT_DOUBLE_EQ(p.z, 2.0); + p = bmOne.getPointCoordsForPointID(10); + EXPECT_DOUBLE_EQ(p.x, 2.0); + EXPECT_DOUBLE_EQ(p.y, 2.0); + EXPECT_DOUBLE_EQ(p.z, 3.0); +} + +TEST_F(BlockMeshTest, GetPartitionBlockIDsSizeOneOneBlock) +{ + std::vector points = {1}; + EXPECT_EQ(bmOne.getPartitionBlockIDs(), points); +} + +TEST_F(BlockMeshTest, GetPartitionBlockIDsSizeOneTwoBlocksInX) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + std::vector ids = {1, 2}; + EXPECT_EQ(bmOne.getPartitionBlockIDs(), ids); +} + +TEST_F(BlockMeshTest, GetPartitionBlockIDsSizeTwoOneBlock) +{ + + part.id = 0; + part.size = 2; + numBlocks.i = 1; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + std::vector ids = {1}; + EXPECT_EQ(bmOne.getPartitionBlockIDs(), ids); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + ids.clear(); + EXPECT_EQ(bmTwo.getPartitionBlockIDs(), ids); +} + +TEST_F(BlockMeshTest, GetPartitionBlockIDsSizeTwoTwoBlocksInY) +{ + part.id = 0; + part.size = 2; + numBlocks.i = 1; + numBlocks.j = 2; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + std::vector ids = {1}; + EXPECT_EQ(bmOne.getPartitionBlockIDs(), ids); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + std::vector idsTwo = {2}; + EXPECT_EQ(bmTwo.getPartitionBlockIDs(), idsTwo); +} + +TEST_F(BlockMeshTest, GetPartitionBlockIDsSizeFourEightBlocks) +{ + part.id = 0; + part.size = 4; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + std::vector ids = {1, 2}; + EXPECT_EQ(bmOne.getPartitionBlockIDs(), ids); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + std::vector idsTwo = {3, 4}; + EXPECT_EQ(bmTwo.getPartitionBlockIDs(), idsTwo); + part.id = 2; + bmThree.init(part, numBlocks, origin); + std::vector idsThree = {5, 6}; + EXPECT_EQ(bmThree.getPartitionBlockIDs(), idsThree); + part.id = 3; + bmFour.init(part, numBlocks, origin); + std::vector idsFour = {7, 8}; + EXPECT_EQ(bmFour.getPartitionBlockIDs(), idsFour); +} + +TEST_F(BlockMeshTest, GetBlockConnectivityPointIDsSizeOneOneBlock) +{ + Iocatalyst::BlockMesh::BlockConn ids = {1, 2, 4, 3, 5, 6, 8, 7}; + EXPECT_EQ(bmOne.getBlockConnectivityPointIDs(1), ids); +} + +TEST_F(BlockMeshTest, GetBlockConnectivityPointIDsSizeOneTwoBlocksInX) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 1; + numBlocks.k = 1; + bmOne.init(part, numBlocks, origin); + Iocatalyst::BlockMesh::BlockConn ids = {2, 3, 6, 5, 8, 9, 12, 11}; + EXPECT_EQ(bmOne.getBlockConnectivityPointIDs(2), ids); +} + +TEST_F(BlockMeshTest, GetBlockConnectivityPointIDsSizeOneEightBlocks) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + Iocatalyst::BlockMesh::BlockConn ids = {14, 15, 18, 17, 23, 24, 27, 26}; + EXPECT_EQ(bmOne.getBlockConnectivityPointIDs(8), ids); + ids = {1, 2, 5, 4, 10, 11, 14, 13}; + EXPECT_EQ(bmOne.getBlockConnectivityPointIDs(1), ids); + ids = {2, 3, 6, 5, 11, 12, 15, 14}; + EXPECT_EQ(bmOne.getBlockConnectivityPointIDs(2), ids); +} + +TEST_F(BlockMeshTest, GetNumPointsSizeFourEightBlocks) +{ + part.id = 0; + part.size = 4; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + EXPECT_EQ(bmOne.getNumPoints(), 27); + EXPECT_EQ(bmOne.getNumPartitionPoints(), 12); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + EXPECT_EQ(bmTwo.getNumPoints(), 27); + EXPECT_EQ(bmTwo.getNumPartitionPoints(), 12); + part.id = 2; + bmThree.init(part, numBlocks, origin); + EXPECT_EQ(bmThree.getNumPoints(), 27); + EXPECT_EQ(bmThree.getNumPartitionPoints(), 12); + part.id = 3; + bmFour.init(part, numBlocks, origin); + EXPECT_EQ(bmFour.getNumPoints(), 27); + EXPECT_EQ(bmFour.getNumPartitionPoints(), 12); +} + +TEST_F(BlockMeshTest, GetNumBlocksSizeFourEightBlocks) +{ + part.id = 0; + part.size = 4; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + EXPECT_EQ(bmOne.getNumBlocks(), 8); + EXPECT_EQ(bmOne.getNumPartitionBlocks(), 2); + part.id = 1; + bmTwo.init(part, numBlocks, origin); + EXPECT_EQ(bmTwo.getNumBlocks(), 8); + EXPECT_EQ(bmTwo.getNumPartitionBlocks(), 2); + part.id = 2; + bmThree.init(part, numBlocks, origin); + EXPECT_EQ(bmThree.getNumBlocks(), 8); + EXPECT_EQ(bmThree.getNumPartitionBlocks(), 2); + part.id = 3; + bmFour.init(part, numBlocks, origin); + EXPECT_EQ(bmFour.getNumBlocks(), 8); + EXPECT_EQ(bmFour.getNumPartitionBlocks(), 2); +} + +TEST_F(BlockMeshTest, GetGlobalIDForBlockID) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + Iocatalyst::BlockMesh::Extent coords = {0, 0, 0}; + Iocatalyst::BlockMesh::ID id = bmOne.getIDfromCoords(coords, bmOne.getGlobalBlockExtents()); + EXPECT_EQ(bmOne.getGlobalIDForBlockID(1), id); + coords = {1, 1, 1}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalBlockExtents()); + EXPECT_EQ(bmOne.getGlobalIDForBlockID(8), id); + + origin.i = 151; + origin.j = 56; + origin.k = 667; + bmOne.init(part, numBlocks, origin); + coords = {origin.i, origin.j, origin.k}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalBlockExtents()); + EXPECT_EQ(bmOne.getGlobalIDForBlockID(1), id); + coords = {origin.i + 1, origin.j, origin.k}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalBlockExtents()); + EXPECT_EQ(bmOne.getGlobalIDForBlockID(2), id); + coords = {origin.i + 1, origin.j + 1, origin.k + 1}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalBlockExtents()); + EXPECT_EQ(bmOne.getGlobalIDForBlockID(8), id); +} + +TEST_F(BlockMeshTest, GetGlobalIDForPointID) +{ + part.id = 0; + part.size = 1; + numBlocks.i = 2; + numBlocks.j = 2; + numBlocks.k = 2; + bmOne.init(part, numBlocks, origin); + Iocatalyst::BlockMesh::Extent coords = {0, 0, 0}; + Iocatalyst::BlockMesh::ID id = bmOne.getIDfromCoords(coords, bmOne.getGlobalPointExtents()); + EXPECT_EQ(bmOne.getGlobalIDForPointID(1), id); + coords = {2, 2, 2}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalPointExtents()); + EXPECT_EQ(bmOne.getGlobalIDForPointID(27), id); + + origin.i = 34; + origin.j = 898; + origin.k = 454; + bmOne.init(part, numBlocks, origin); + coords = {origin.i, origin.j, origin.k}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalPointExtents()); + EXPECT_EQ(bmOne.getGlobalIDForPointID(1), id); + coords = {origin.i + 1, origin.j, origin.k}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalPointExtents()); + EXPECT_EQ(bmOne.getGlobalIDForPointID(2), id); + coords = {origin.i + 2, origin.j + 2, origin.k + 2}; + id = bmOne.getIDfromCoords(coords, bmOne.getGlobalPointExtents()); + EXPECT_EQ(bmOne.getGlobalIDForPointID(27), id); +} diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_DatabaseIOTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_DatabaseIOTest.C new file mode 100644 index 0000000000..e203091c0c --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_DatabaseIOTest.C @@ -0,0 +1,133 @@ +// Copyright(C) 1999-2021 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Iocatalyst_DatabaseIOTest::Iocatalyst_DatabaseIOTest() +{ + part.id = putils.parallel_rank(); + part.size = putils.parallel_size(); + blockMeshSize.i = 2; + blockMeshSize.j = 2; + blockMeshSize.k = 2; + origin.i = 0; + origin.j = 0; + origin.k = 0; +} + +bool Iocatalyst_DatabaseIOTest::regionsAreEqual(const std::string &fileName, + const std::string &catFileName, + const std::string &iossDatabaseType) +{ + Ioss::PropertyManager dbProps; + auto inputFileName = fileName; + auto inputCatalystFileName = catFileName; + Ioss::ParallelUtils pu; + int numRanks = pu.parallel_size(); + int rank = pu.parallel_rank(); + if (iossDatabaseType == EXODUS_DATABASE_TYPE && numRanks > 1) { + inputFileName += "." + std::to_string(numRanks) + "." + std::to_string(rank); + inputCatalystFileName += "." + std::to_string(numRanks) + "." + std::to_string(rank); + } + Ioss::DatabaseIO *dbi = + Ioss::IOFactory::create(iossDatabaseType, inputFileName, Ioss::READ_RESTART, + Ioss::ParallelUtils::comm_self(), dbProps); + if (dbi == nullptr || !dbi->ok(true)) { + return false; + } + + Ioss::PropertyManager dbCatProps; + Ioss::DatabaseIO *dbiCat = + Ioss::IOFactory::create(iossDatabaseType, inputCatalystFileName, Ioss::READ_RESTART, + Ioss::ParallelUtils::comm_self(), dbCatProps); + if (dbiCat == nullptr || !dbiCat->ok(true)) { + return false; + } + + Ioss::Region ir(dbi); + Ioss::Region rCat(dbiCat); + Ioss::MeshCopyOptions options; + options.data_storage_type = 1; + return Ioss::Compare::compare_database(ir, rCat, options); +} + +void Iocatalyst_DatabaseIOTest::runStructuredTest(const std::string &testName) +{ + std::string cgnsFileName = + testName + CATALYST_TEST_FILE_NP + std::to_string(part.size) + CGNS_FILE_EXTENSION; + std::string catalystFileName = CATALYST_TEST_FILE_PREFIX + testName + CATALYST_TEST_FILE_NP + + std::to_string(part.size) + CGNS_FILE_EXTENSION; + Iocatalyst::BlockMeshSet::IOSSparams iop(cgnsFileName, CGNS_DATABASE_TYPE); + bmSet.writeIOSSFile(iop); + iop.fileName = catalystFileName; + bmSet.writeCatalystIOSSFile(iop); + checkZeroCopyFields(iop); + EXPECT_TRUE(regionsAreEqual(cgnsFileName, catalystFileName, CGNS_DATABASE_TYPE)); +} + +void Iocatalyst_DatabaseIOTest::runUnstructuredTest(const std::string &testName) +{ + std::string exodusFileName = + testName + CATALYST_TEST_FILE_NP + std::to_string(part.size) + EXODUS_FILE_EXTENSION; + std::string catalystFileName = CATALYST_TEST_FILE_PREFIX + testName + CATALYST_TEST_FILE_NP + + std::to_string(part.size) + EXODUS_FILE_EXTENSION; + Iocatalyst::BlockMeshSet::IOSSparams iop(exodusFileName, EXODUS_DATABASE_TYPE); + bmSet.writeIOSSFile(iop); + iop.fileName = catalystFileName; + bmSet.writeCatalystIOSSFile(iop); + checkZeroCopyFields(iop); + EXPECT_TRUE(regionsAreEqual(exodusFileName, catalystFileName, EXODUS_DATABASE_TYPE)); +} + +void Iocatalyst_DatabaseIOTest::checkZeroCopyFields(Iocatalyst::BlockMeshSet::IOSSparams &iop) +{ + Ioss::PropertyManager cdbProps; + cdbProps.add(Ioss::Property("CATALYST_CONDUIT_NODE", iop.getCatalystConduitNode())); + + Ioss::DatabaseIO *cdbi = + Ioss::IOFactory::create(Iocatalyst::BlockMeshSet::CATALYST_DATABASE_TYPE, + Iocatalyst::BlockMeshSet::CATALYST_DUMMY_DATABASE, Ioss::READ_RESTART, + Ioss::ParallelUtils::comm_world(), cdbProps); + if (cdbi == nullptr || !cdbi->ok(true)) { + return; + } + + Ioss::Region cir(cdbi); + Iocatalyst::DatabaseIO::RegionContainer rc; + rc.push_back(&cir); + checkEntityContainerZeroCopyFields(rc); + checkEntityContainerZeroCopyFields(cir.get_node_blocks()); + checkEntityContainerZeroCopyFields(cir.get_element_blocks()); + checkEntityContainerZeroCopyFields(cir.get_structured_blocks()); +} + +void Iocatalyst_DatabaseIOTest::setBlockMeshSize(unsigned int i, unsigned int j, unsigned int k) +{ + blockMeshSize.i = i; + blockMeshSize.j = j; + blockMeshSize.k = k; +} + +void Iocatalyst_DatabaseIOTest::setOrigin(unsigned int i, unsigned int j, unsigned int k) +{ + origin.i = i; + origin.j = j; + origin.k = k; +} + +void Iocatalyst_DatabaseIOTest::addBlockMesh(Iocatalyst::BlockMesh &blockMesh) +{ + blockMesh.init(part, blockMeshSize, origin); + bmSet.addBlockMesh(blockMesh); +} \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_DatabaseIOTest.h b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_DatabaseIOTest.h new file mode 100644 index 0000000000..a9ce4cc0b9 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_DatabaseIOTest.h @@ -0,0 +1,66 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#pragma once + +#include "iocatalyst_export.h" + +#include "gtest/gtest.h" +#include +#include + +class IOCATALYST_EXPORT Iocatalyst_DatabaseIOTest : public ::testing::Test +{ +protected: + Iocatalyst::BlockMeshSet bmSet; + Iocatalyst::BlockMesh::Partition part; + Iocatalyst::BlockMesh::Extent blockMeshSize; + Iocatalyst::BlockMesh::Extent origin; + Ioss::ParallelUtils putils; + + Iocatalyst_DatabaseIOTest(); + + bool regionsAreEqual(const std::string &fileName, const std::string &catFileName, + const std::string &iossDatabaseType); + + void runStructuredTest(const std::string &testName); + + void runUnstructuredTest(const std::string &testName); + + void checkZeroCopyFields(Iocatalyst::BlockMeshSet::IOSSparams &iop); + + template + void checkEntityContainerZeroCopyFields(const EntityContainer &ge) + { + for (auto g : ge) { + auto nameList = g->field_describe(); + for (auto name : nameList) { + auto field = g->get_fieldref(name); + if (field.zero_copy_enabled()) { + std::vector dcBuffer(field.get_size()); + g->get_field_data(name, dcBuffer.data(), dcBuffer.size()); + void *data; + size_t dataSize; + g->get_field_data(name, &data, &dataSize); + std::byte *b = static_cast(data); + std::vector zcBuffer(b, b + field.get_size()); + EXPECT_EQ(dcBuffer, zcBuffer); + } + } + } + } + + void setBlockMeshSize(unsigned int i, unsigned int j, unsigned int k); + void setOrigin(unsigned int i, unsigned int j, unsigned int k); + void addBlockMesh(Iocatalyst::BlockMesh &blockMesh); + + const std::string CGNS_DATABASE_TYPE = "cgns"; + const std::string CGNS_FILE_EXTENSION = ".cgns"; + const std::string EXODUS_DATABASE_TYPE = "exodus"; + const std::string EXODUS_FILE_EXTENSION = ".ex2"; + const std::string CATALYST_TEST_FILE_PREFIX = "catalyst_"; + const std::string CATALYST_TEST_FILE_NP = "_np_"; +}; diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_ElementBlockTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_ElementBlockTest.C new file mode 100644 index 0000000000..1541359134 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_ElementBlockTest.C @@ -0,0 +1,61 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include + +TEST_F(Iocatalyst_DatabaseIOTest, WriteThreeElementBlocksWith24Cells) +{ + Iocatalyst::BlockMesh bmOne; + setBlockMeshSize(2, 2, 2); + addBlockMesh(bmOne); + + Iocatalyst::BlockMesh bmTwo; + setOrigin(2, 0, 0); + setBlockMeshSize(2, 2, 2); + addBlockMesh(bmTwo); + + Iocatalyst::BlockMesh bmThree; + setOrigin(4, 0, 0); + setBlockMeshSize(2, 2, 2); + addBlockMesh(bmThree); + + runUnstructuredTest("test_eb_3_cells_24"); +} + +TEST_F(Iocatalyst_DatabaseIOTest, WriteOneElementBlockWith8Cells) +{ + Iocatalyst::BlockMesh bm; + setBlockMeshSize(2, 2, 2); + addBlockMesh(bm); + runUnstructuredTest("test_eb_1_cells_8"); +} + +TEST_F(Iocatalyst_DatabaseIOTest, WriteOneElementBlockWith300Cells) +{ + Iocatalyst::BlockMesh bm; + setBlockMeshSize(10, 10, 3); + addBlockMesh(bm); + runUnstructuredTest("test_eb_1_cells_300"); +} + +TEST_F(Iocatalyst_DatabaseIOTest, WriteThreeElementBlocksWith835Cells) +{ + Iocatalyst::BlockMesh bmOne; + setBlockMeshSize(5, 15, 3); + addBlockMesh(bmOne); + + Iocatalyst::BlockMesh bmTwo; + setOrigin(5, 0, 0); + setBlockMeshSize(8, 14, 4); + addBlockMesh(bmTwo); + + Iocatalyst::BlockMesh bmThree; + setOrigin(13, 0, 0); + setBlockMeshSize(3, 6, 9); + addBlockMesh(bmThree); + + runUnstructuredTest("test_eb_3_cells_835"); +} \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_LoggingTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_LoggingTest.C new file mode 100644 index 0000000000..8d1105c9b8 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_LoggingTest.C @@ -0,0 +1,166 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include + +TEST_F(LoggingTest, Defaults) +{ + EXPECT_FALSE(log.isCatalystLoggingON()); + EXPECT_EQ(log.getLogFileName(), log.getDefaultLogFileName()); + EXPECT_EQ(log.getLogOutputDirectoryPath(), log.getDefaultLogOutputDirectoryPath()); +} + +TEST_F(LoggingTest, CatalystLoggingEnabled) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_FILE_NAME", "foo.csv")); + props.add(Ioss::Property("CATALYST_LOGGING_OUTPUT_DIRECTORY_PATH", "/projects/bar/")); + log.setProperties(&props); + + EXPECT_TRUE(log.isCatalystLoggingON()); + EXPECT_EQ(log.getLogFileName(), "foo.csv"); + EXPECT_EQ(log.getLogOutputDirectoryPath(), "/projects/bar/"); +} + +TEST_F(LoggingTest, WriteLogDefault) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + log.setProperties(&props); + + if (log.isCatalystLoggingON()) { + log.writeToLogFile(); + } + + checkTestOutputFileExists(log.getLogFileName().c_str()); + std::vector> lfc = log.readLogFile(); + + EXPECT_EQ(lfc.size(), 0); +} + +TEST_F(LoggingTest, WriteLogOnceWithAllSupportedPropertyTypes) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "foo")); + props.add(Ioss::Property("CATALYST_LOGGING_INTEGER_PROP", 6)); + props.add(Ioss::Property("CATALYST_LOGGING_REAL_PROP", 3.7556)); + log.setProperties(&props); + + std::vector logLine; + if (log.isCatalystLoggingON()) { + logLine = log.writeToLogFile(); + } + + checkTestOutputFileExists(log.getLogFileName().c_str()); + std::vector> lfc = log.readLogFile(); + + ASSERT_EQ(lfc.size(), 2); + EXPECT_EQ(lfc[0], log.getLogFileHeaders()); + EXPECT_EQ(lfc[1], logLine); +} + +TEST_F(LoggingTest, WriteLogTwiceWithAllSupportedPropertyTypes) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "bar")); + props.add(Ioss::Property("CATALYST_LOGGING_INTEGER_PROP", 12)); + props.add(Ioss::Property("CATALYST_LOGGING_REAL_PROP", 7.45454)); + log.setProperties(&props); + + std::vector logLineOne; + if (log.isCatalystLoggingON()) { + logLineOne = log.writeToLogFile(); + } + + Ioss::PropertyManager propsTwo; + propsTwo.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + propsTwo.add(Ioss::Property("CATALYST_LOGGING_REAL_PROP", 90.3)); + propsTwo.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "foo")); + propsTwo.add(Ioss::Property("CATALYST_LOGGING_INTEGER_PROP", 107)); + log.setProperties(&propsTwo); + + std::vector logLineTwo; + if (log.isCatalystLoggingON()) { + logLineTwo = log.writeToLogFile(); + } + + checkTestOutputFileExists(log.getLogFileName().c_str()); + std::vector> lfc = log.readLogFile(); + + ASSERT_EQ(lfc.size(), 3); + EXPECT_EQ(lfc[0], log.getLogFileHeaders()); + EXPECT_EQ(lfc[1], logLineOne); + EXPECT_EQ(lfc[2], logLineTwo); +} + +TEST_F(LoggingTest, WriteLogWithUnsupportedPropertyTypes) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "bar")); + int ten = 10; + props.add(Ioss::Property("CATALYST_LOGGING_POINTER_PROP", (void *)&ten)); + std::vector iv = {1, 2, 3}; + props.add(Ioss::Property("CATALYST_LOGGING_VEC_INTEGER_PROP", iv)); + std::vector dv = {1.4, 2.2, -56.3}; + props.add(Ioss::Property("CATALYST_LOGGING_VEC_DOUBLE_PROP", dv)); + log.setProperties(&props); + + std::vector logLine; + if (log.isCatalystLoggingON()) { + logLine = log.writeToLogFile(); + } + + checkTestOutputFileExists(log.getLogFileName().c_str()); + std::vector> lfc = log.readLogFile(); + + std::vector h = {"STRING_PROP"}; + EXPECT_EQ(h, log.getLogFileHeaders()); + ASSERT_EQ(lfc.size(), 2); + EXPECT_EQ(lfc[0], log.getLogFileHeaders()); + EXPECT_EQ(lfc[1], logLine); +} + +TEST_F(LoggingTest, WriteLogWithQuotedCommas) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "foo")); + props.add(Ioss::Property("CATALYST_LOGGING_QUOTED_COMMA_PROP", "\"8,7,go,3.2\"")); + props.add(Ioss::Property("CATALYST_LOGGING_QUOTED_ANOTHER_COMMA_PROP", + "This address \", 343 Far Lane, ND 8732, RT 3\"")); + log.setProperties(&props); + + std::vector logLine; + if (log.isCatalystLoggingON()) { + logLine = log.writeToLogFile(); + } + + checkTestOutputFileExists(log.getLogFileName().c_str()); + std::vector> lfc = log.readLogFile(); + + ASSERT_EQ(lfc.size(), 2); + EXPECT_EQ(lfc[0], log.getLogFileHeaders()); + EXPECT_EQ(lfc[1], logLine); +} + +TEST_F(LoggingTest, WriteLogWithQuotedQuotes) +{ + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "bar")); + props.add(Ioss::Property("CATALYST_LOGGING_QUOTED_QUOTE_PROP", "\"\"foo\"\" bar \"1,3,2\"")); + props.add(Ioss::Property("CATALYST_LOGGING_ANOTHER_QUOTED_QUOTE_PROP", "This has \"\"quote\"\"")); + log.setProperties(&props); + + std::vector logLine; + if (log.isCatalystLoggingON()) { + logLine = log.writeToLogFile(); + } + + checkTestOutputFileExists(log.getLogFileName().c_str()); + std::vector> lfc = log.readLogFile(); + + ASSERT_EQ(lfc.size(), 2); + EXPECT_EQ(lfc[0], log.getLogFileHeaders()); + EXPECT_EQ(lfc[1], logLine); +} \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_LoggingTest.h b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_LoggingTest.h new file mode 100644 index 0000000000..e90e761c70 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_LoggingTest.h @@ -0,0 +1,32 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#pragma once + +#include "gtest/gtest.h" +#include + +class LoggingTest : public ::testing::Test +{ +protected: + Iocatalyst::CatalystLogging log; + Ioss::PropertyManager props; + + ~LoggingTest() { remove(log.getLogFileName().c_str()); } + + void checkTestOutputFileExists(const char *fileName) { EXPECT_TRUE(isFileExists(fileName)); } + + bool isFileExists(const char *fileName) + { + FILE *fp = fopen(fileName, "r"); + bool outputFileExists = false; + if (fp != NULL) { + outputFileExists = true; + fclose(fp); + } + return outputFileExists; + } +}; \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_ManagerTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_ManagerTest.C new file mode 100644 index 0000000000..8093282acd --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_ManagerTest.C @@ -0,0 +1,547 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace Iocatalyst; + +class ManagerTest : public ::testing::Test +{ +protected: + Ioss::PropertyManager props; + Ioss::ParallelUtils putils; + CatalystManager::CatalystProps catalystProps; + CatalystManager::CatalystPipelineID id; + conduit_cpp::Node n; + void reset() { CatalystManager::getInstance().reset(); } + void initialize() + { + id = CatalystManager::getInstance().initialize(props, putils); + catalystProps = CatalystManager::getInstance().getCatalystProps(id); + } + + void compareConduit(const conduit_cpp::Node &n, const conduit_cpp::Node &m) + { + EXPECT_EQ(n.to_string(), m.to_string()); + } + + void checkExecuteProps(const conduit_cpp::Node &n, CatalystManager::CatalystProps &p, int state, + double time) + { + auto csp = CatalystManager::getInstance().getCatStatePath(); + EXPECT_EQ(n[csp + CatalystManager::TIMESTEP].as_int(), state - 1); + EXPECT_EQ(n[csp + CatalystManager::CYCLE].as_int(), state - 1); + EXPECT_EQ(n[csp + CatalystManager::TIME].as_double(), time); + auto sn = std::to_string(p.catalystPipelineID); + EXPECT_EQ(n[csp + CatalystManager::PIPELINES + CatalystManager::FS + sn].as_string(), sn); + } + + void checkExecuteData(const conduit_cpp::Node &n, std::string &channel_name, int state, + double time, const conduit_cpp::Node &m) + { + auto ccp = CatalystManager::getInstance().getCatChannelsPath(); + auto ip = ccp + channel_name + CatalystManager::FS; + EXPECT_EQ(n[ip + CatalystManager::TYPE].as_string(), CatalystManager::IOSS); + auto dp = ip + CatalystManager::FS + CatalystManager::DATA; + conduit_cpp::Node d; + d.set_node(n[dp]); + d.remove(CatalystManager::TIMESTEP); + d.remove(CatalystManager::CYCLE); + d.remove(CatalystManager::TIME); + compareConduit(d, m); + EXPECT_DOUBLE_EQ(n[dp + CatalystManager::FS + CatalystManager::TIME].as_double(), time); + EXPECT_EQ(n[dp + CatalystManager::FS + CatalystManager::CYCLE].as_int(), state - 1); + EXPECT_EQ(n[dp + CatalystManager::FS + CatalystManager::TIMESTEP].as_int(), state - 1); + } +}; + +TEST_F(LoggingTest, LoggingDefault) +{ + Ioss::ParallelUtils putils; + CatalystManager::getInstance().writeToCatalystLogFile(putils, props); + EXPECT_FALSE(isFileExists(CatalystLogging::getDefaultLogFileName().c_str())); +} + +TEST_F(LoggingTest, LoggingNotEnabled) +{ + Ioss::ParallelUtils putils; + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", false)); + CatalystManager::getInstance().writeToCatalystLogFile(putils, props); + EXPECT_FALSE(isFileExists(CatalystLogging::getDefaultLogFileName().c_str())); +} + +TEST_F(LoggingTest, LoggingEnabled) +{ + Ioss::ParallelUtils putils; + props.add(Ioss::Property("CATALYST_LOGGING_ENABLED", true)); + props.add(Ioss::Property("CATALYST_LOGGING_STRING_PROP", "foo")); + props.add(Ioss::Property("CATALYST_LOGGING_INTEGER_PROP", 6)); + props.add(Ioss::Property("CATALYST_LOGGING_REAL_PROP", 3.7556)); + CatalystManager::getInstance().writeToCatalystLogFile(putils, props); + EXPECT_TRUE(isFileExists(CatalystLogging::getDefaultLogFileName().c_str())); +} + +TEST_F(ManagerTest, CatalystPipelineID) +{ + initialize(); + EXPECT_EQ(catalystProps.catalystPipelineID, 0); + + initialize(); + EXPECT_EQ(catalystProps.catalystPipelineID, 1); + + initialize(); + EXPECT_EQ(catalystProps.catalystPipelineID, 2); +} + +TEST_F(ManagerTest, CATALYST_BLOCK_PARSE_JSON_STRING) +{ + std::string jsonScript = "{foo: 12}"; + props.add(Ioss::Property("CATALYST_BLOCK_PARSE_JSON_STRING", jsonScript)); + initialize(); + EXPECT_EQ(catalystProps.catalystBlockJSON, jsonScript); +} + +TEST_F(ManagerTest, PHACTORI_JSON_SCRIPT) +{ + std::string jsonFileName = "jsonFile.json"; + std::string jsonScript = "{foo: 12}"; + std::ofstream jsonFile; + jsonFile.open(jsonFileName); + jsonFile << jsonScript; + jsonFile.close(); + props.add(Ioss::Property(CatalystManager::PHACTORI_JSON_SCRIPT, jsonFileName)); + initialize(); + EXPECT_EQ(catalystProps.catalystBlockJSON, jsonScript); + remove(jsonFileName.c_str()); +} + +TEST_F(ManagerTest, CATALYST_SCRIPT) +{ + initialize(); + EXPECT_EQ(catalystProps.catalystPythonFilename, + CatalystManager::getInstance().getCatalystPythonDriverPath()); + + std::string catalystFileName = "/path/to/file/catalystFile.txt"; + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT, catalystFileName)); + initialize(); + EXPECT_EQ(catalystProps.catalystPythonFilename, catalystFileName); +} + +TEST_F(ManagerTest, CATALYST_SCRIPT_EXTRA_FILE) +{ + std::string extraFileName = "extraFileName.txt"; + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT_EXTRA_FILE, extraFileName)); + initialize(); + EXPECT_EQ(catalystProps.catalystScriptExtraFile, extraFileName); +} + +TEST_F(ManagerTest, CATALYST_BLOCK_PARSE_INPUT_DECK_NAME) +{ + std::string inputDeckName = "contact.i"; + props.add(Ioss::Property(CatalystManager::CATALYST_BLOCK_PARSE_INPUT_DECK_NAME, inputDeckName)); + initialize(); + EXPECT_EQ(catalystProps.catalystInputDeckName, inputDeckName); +} + +TEST_F(ManagerTest, CATALYST_ENABLE_LOGGING) +{ + initialize(); + EXPECT_FALSE(catalystProps.enableLogging); + + props.add(Ioss::Property(CatalystManager::CATALYST_ENABLE_LOGGING, true)); + initialize(); + EXPECT_TRUE(catalystProps.enableLogging); +} + +TEST_F(ManagerTest, CATALYST_DEBUG_LEVEL) +{ + initialize(); + EXPECT_EQ(catalystProps.debugLevel, 0); + + props.add(Ioss::Property(CatalystManager::CATALYST_DEBUG_LEVEL, 3)); + initialize(); + EXPECT_EQ(catalystProps.debugLevel, 3); +} + +TEST_F(ManagerTest, CATALYST_OUTPUT_DIRECTORY) +{ + initialize(); + EXPECT_EQ(catalystProps.catalystOutputDirectory, + CatalystManager::getInstance().CATALYST_OUTPUT_DEFAULT); + + std::string catalystOutputDirectory = "catalyst"; + props.add(Ioss::Property(CatalystManager::CATALYST_OUTPUT_DIRECTORY, catalystOutputDirectory)); + initialize(); + EXPECT_EQ(catalystProps.catalystOutputDirectory, catalystOutputDirectory); +} + +TEST_F(ManagerTest, CATALYST_INPUT_NAME) +{ + initialize(); + EXPECT_EQ(catalystProps.catalystInputName, CatalystManager::getInstance().CATALYST_INPUT_DEFAULT); + + std::string catalystInputName = "mesh"; + props.add(Ioss::Property(CatalystManager::CATALYST_INPUT_NAME, catalystInputName)); + initialize(); + EXPECT_EQ(catalystProps.catalystInputName, catalystInputName); +} + +TEST_F(ManagerTest, CATALYST_MULTI_INPUT_PIPELINE_NAME) +{ + initialize(); + EXPECT_FALSE(catalystProps.enableCatalystMultiInputPipeline); + + std::string catalystMultiInputPipelineName = "multi"; + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, + catalystMultiInputPipelineName)); + initialize(); + EXPECT_EQ(catalystProps.catalystMultiInputPipelineName, catalystMultiInputPipelineName); + EXPECT_TRUE(catalystProps.enableCatalystMultiInputPipeline); +} + +TEST_F(ManagerTest, InitializeConduitDefault) +{ + reset(); + compareConduit(CatalystManager::getInstance().getInitializeConduit(), n); +} + +TEST_F(ManagerTest, InitializeConduitCatalystFile) +{ + reset(); + std::string catalystFileName = "/path/to/file/catalystFile.txt"; + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT, catalystFileName)); + initialize(); + CatalystManager::getInstance().addScriptProps(n, catalystProps); + compareConduit(CatalystManager::getInstance().getInitializeConduit(), n); +} + +TEST_F(ManagerTest, InitializeConduitPhactoriJSON) +{ + reset(); + std::string js = "some json"; + props.add(Ioss::Property(CatalystManager::CATALYST_BLOCK_PARSE_JSON_STRING, js)); + props.add(Ioss::Property(CatalystManager::CATALYST_INPUT_NAME, "data")); + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT_EXTRA_FILE, "extra")); + props.add(Ioss::Property(CatalystManager::CATALYST_BLOCK_PARSE_INPUT_DECK_NAME, "adagio")); + props.add(Ioss::Property(CatalystManager::CATALYST_OUTPUT_DIRECTORY, "temp")); + props.add(Ioss::Property(CatalystManager::CATALYST_ENABLE_LOGGING, true)); + props.add(Ioss::Property(CatalystManager::CATALYST_DEBUG_LEVEL, 11)); + initialize(); + CatalystManager::getInstance().addScriptProps(n, catalystProps); + compareConduit(CatalystManager::getInstance().getInitializeConduit(), n); +} + +TEST_F(ManagerTest, InitializeConduitMultipleScripts) +{ + reset(); + std::string catalystFileName = "/path/to/file/catalystFile.txt"; + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT, catalystFileName)); + initialize(); + + Ioss::PropertyManager propsOne; + std::string otherFile = "/path/to/other/file"; + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT, otherFile)); + auto idOne = CatalystManager::getInstance().initialize(propsOne, putils); + auto catPropsOne = CatalystManager::getInstance().getCatalystProps(idOne); + + Ioss::PropertyManager propsTwo; + std::string js = "json"; + props.add(Ioss::Property(CatalystManager::CATALYST_BLOCK_PARSE_JSON_STRING, js)); + idOne = CatalystManager::getInstance().initialize(propsOne, putils); + auto catPropsTwo = CatalystManager::getInstance().getCatalystProps(idOne); + + CatalystManager::getInstance().addScriptProps(n, catalystProps); + CatalystManager::getInstance().addScriptProps(n, catPropsOne); + CatalystManager::getInstance().addScriptProps(n, catPropsTwo); + compareConduit(CatalystManager::getInstance().getInitializeConduit(), n); +} + +TEST_F(ManagerTest, ExecuteConduitOneScript) +{ + reset(); + std::string catalystFileName = "/path/to/file/catalystFile.txt"; + props.add(Ioss::Property(CatalystManager::CATALYST_SCRIPT, catalystFileName)); + initialize(); + + conduit_cpp::Node m; + int state = 2; + double time = 10.4; + m["some/data"] = 32; + CatalystManager::getInstance().addExecuteProps(n, catalystProps, state, time); + CatalystManager::getInstance().addExecuteData(n, catalystProps.catalystInputName, state, time, m); + checkExecuteProps(n, catalystProps, state, time); + checkExecuteData(n, catalystProps.catalystInputName, state, time, m); +} + +TEST_F(ManagerTest, ExecuteConduitInputName) +{ + reset(); + props.add(Ioss::Property(CatalystManager::CATALYST_INPUT_NAME, "dataset")); + initialize(); + + int state = 10; + double time = 4.5; + conduit_cpp::Node m; + m["other/data"] = 90; + CatalystManager::getInstance().addExecuteProps(n, catalystProps, state, time); + CatalystManager::getInstance().addExecuteData(n, catalystProps.catalystInputName, state, time, m); + checkExecuteProps(n, catalystProps, state, time); + checkExecuteData(n, catalystProps.catalystInputName, state, time, m); +} + +TEST_F(ManagerTest, ManagerStateDefault) +{ + reset(); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mInit); +} + +TEST_F(ManagerTest, InvalidIDGetCatalystProps) +{ + reset(); + EXPECT_THROW(CatalystManager::getInstance().getCatalystProps(1), std::runtime_error); +} + +TEST_F(ManagerTest, ManagerExecuteStateChange) +{ + reset(); + initialize(); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mInit); + + conduit_cpp::Node m; + CatalystManager::getInstance().execute(catalystProps.catalystPipelineID, 2, 10.2, m); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mExecute); + + EXPECT_THROW(CatalystManager::getInstance().initialize(props, putils), std::runtime_error); +} + +TEST_F(ManagerTest, ManagerPipelineState) +{ + reset(); + initialize(); + EXPECT_EQ(CatalystManager::getInstance().getPipelineState(catalystProps.catalystPipelineID), + CatalystManager::pExecute); +} + +TEST_F(ManagerTest, ManagerFinalizeStateChange) +{ + reset(); + initialize(); + CatalystManager::getInstance().finalize(catalystProps.catalystPipelineID); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mFinalize); + EXPECT_EQ(CatalystManager::getInstance().getPipelineState(catalystProps.catalystPipelineID), + CatalystManager::pFinalize); + EXPECT_THROW(CatalystManager::getInstance().initialize(props, putils), std::runtime_error); + conduit_cpp::Node m; + EXPECT_THROW(CatalystManager::getInstance().execute(catalystProps.catalystPipelineID, 2, 10.2, m), + std::runtime_error); +} + +TEST_F(ManagerTest, ManagerFinalizeStateChangeMultipleScripts) +{ + reset(); + initialize(); + + auto idOne = CatalystManager::getInstance().initialize(props, putils); + auto idTwo = CatalystManager::getInstance().initialize(props, putils); + + CatalystManager::getInstance().finalize(catalystProps.catalystPipelineID); + EXPECT_EQ(CatalystManager::getInstance().getPipelineState(catalystProps.catalystPipelineID), + CatalystManager::pFinalize); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mExecute); + + conduit_cpp::Node m; + CatalystManager::getInstance().execute(idOne, 2, 10.2, m); + CatalystManager::getInstance().finalize(idOne); + EXPECT_EQ(CatalystManager::getInstance().getPipelineState(idOne), CatalystManager::pFinalize); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mExecute); + EXPECT_THROW(CatalystManager::getInstance().execute(idOne, 2, 10.2, m), std::runtime_error); + + CatalystManager::getInstance().finalize(idTwo); + EXPECT_EQ(CatalystManager::getInstance().getPipelineState(idTwo), CatalystManager::pFinalize); + EXPECT_EQ(CatalystManager::getInstance().getManagerState(), CatalystManager::mFinalize); +} + +TEST_F(ManagerTest, ManagerGetCatDataPath) +{ + EXPECT_EQ(CatalystManager::getInstance().getCatDataPath(props), "catalyst/channels/input/data"); + std::string name = "foo"; + props.add(Ioss::Property(CatalystManager::CATALYST_INPUT_NAME, name)); + EXPECT_EQ(CatalystManager::getInstance().getCatDataPath(props), "catalyst/channels/foo/data"); +} + +TEST_F(ManagerTest, ManagerMultiInputStateChange) +{ + reset(); + std::string catalystMultiInputPipelineName = "multi"; + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, + catalystMultiInputPipelineName)); + initialize(); + EXPECT_EQ(catalystProps.enableCatalystMultiInputPipeline, true); + EXPECT_EQ(catalystProps.catalystMultiInputPipelineName, catalystMultiInputPipelineName); + n["my/data"] = 12; + int state = 12; + double time = 55.3; + CatalystManager::getInstance().setMultiInputWaitState(id, state, time, n); + auto p = CatalystManager::getInstance().getCatalystProps(id); + EXPECT_EQ(p.pipelineState, CatalystManager::pWaitExecute); + compareConduit(p.data, n); + EXPECT_EQ(p.state, state); + EXPECT_DOUBLE_EQ(p.time, time); +} + +TEST_F(ManagerTest, ManagerSetMultiInputStateError) +{ + reset(); + initialize(); + EXPECT_THROW(CatalystManager::getInstance().setMultiInputWaitState(id, 2, 7.6, n), + std::runtime_error); +} + +TEST_F(ManagerTest, ManagerCanExecuteMultiInputScriptError) +{ + reset(); + initialize(); + EXPECT_THROW(CatalystManager::getInstance().canExecuteMultiInputScript(id), std::runtime_error); +} + +TEST_F(ManagerTest, ManagerCanExecuteMultiInputScriptOneNoState) +{ + reset(); + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, "multi")); + initialize(); + EXPECT_FALSE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); +} + +TEST_F(ManagerTest, ManagerCanExecuteMultiInputScriptOne) +{ + reset(); + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, "multi")); + initialize(); + CatalystManager::getInstance().setMultiInputWaitState(id, 3, 5.6, n); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); +} + +TEST_F(ManagerTest, ManagerCanExecuteMultiInputScriptFour) +{ + reset(); + std::string name = "multi"; + int state = 2; + double time = 8.9; + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, name)); + initialize(); + CatalystManager::getInstance().setMultiInputWaitState(id, state, time, n); + + Ioss::PropertyManager propsOne; + CatalystManager::getInstance().initialize(propsOne, putils); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); + + Ioss::PropertyManager propsTwo; + propsTwo.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, name)); + auto idTwo = CatalystManager::getInstance().initialize(propsTwo, putils); + EXPECT_FALSE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); + CatalystManager::getInstance().setMultiInputWaitState(idTwo, state, time, n); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(idTwo)); + + Ioss::PropertyManager propsThree; + propsThree.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, "foo")); + auto idThree = CatalystManager::getInstance().initialize(propsThree, putils); + EXPECT_FALSE(CatalystManager::getInstance().canExecuteMultiInputScript(idThree)); + CatalystManager::getInstance().setMultiInputWaitState(idThree, state, time, n); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(idThree)); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); +} + +TEST_F(ManagerTest, ManagerClearAllMultiInputWaitStatesError) +{ + reset(); + initialize(); + EXPECT_THROW(CatalystManager::getInstance().clearAllMultiInputWaitStates(id), std::runtime_error); +} + +TEST_F(ManagerTest, ManagerClearAllMultiInputWaitStatesOne) +{ + reset(); + std::string name = "multi"; + int state = 2; + double time = 8.9; + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, name)); + initialize(); + n["my/value"] = 13.1; + CatalystManager::getInstance().setMultiInputWaitState(id, 3, 9.2, n); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); + auto p = CatalystManager::getInstance().getCatalystProps(id); + compareConduit(p.data, n); + CatalystManager::getInstance().clearAllMultiInputWaitStates(id); + EXPECT_FALSE(CatalystManager::getInstance().canExecuteMultiInputScript(id)); + p = CatalystManager::getInstance().getCatalystProps(id); + compareConduit(p.data, conduit_cpp::Node()); +} + +TEST_F(ManagerTest, ManagerClearAllMultiInputWaitStatesThree) +{ + reset(); + std::string name = "multi"; + int state = 2; + double time = 8.9; + props.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, name)); + initialize(); + CatalystManager::getInstance().setMultiInputWaitState(id, state, time, n); + + Ioss::PropertyManager propsOne; + CatalystManager::getInstance().initialize(propsOne, putils); + + Ioss::PropertyManager propsTwo; + propsTwo.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, name)); + auto idTwo = CatalystManager::getInstance().initialize(propsTwo, putils); + CatalystManager::getInstance().setMultiInputWaitState(idTwo, state, time, n); + + Ioss::PropertyManager propsThree; + propsThree.add(Ioss::Property(CatalystManager::CATALYST_MULTI_INPUT_PIPELINE_NAME, "foo")); + auto idThree = CatalystManager::getInstance().initialize(propsThree, putils); + CatalystManager::getInstance().setMultiInputWaitState(idThree, state, time, n); + + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(idTwo)); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(idThree)); + + CatalystManager::getInstance().clearAllMultiInputWaitStates(id); + EXPECT_FALSE(CatalystManager::getInstance().canExecuteMultiInputScript(idTwo)); + EXPECT_TRUE(CatalystManager::getInstance().canExecuteMultiInputScript(idThree)); + + CatalystManager::getInstance().clearAllMultiInputWaitStates(idThree); + EXPECT_FALSE(CatalystManager::getInstance().canExecuteMultiInputScript(idThree)); +} + +TEST_F(ManagerTest, ManagerAddExecuteDataThreeInputs) +{ + int state = 6; + double time = 20.2; + conduit_cpp::Node m; + m["other/data"] = 90; + + conduit_cpp::Node m1; + std::string m1Channel = "m1"; + m1["m1/data"] = 100; + + conduit_cpp::Node m2; + std::string m2Channel = "m2"; + m2["m2/data"] = 500; + + CatalystManager::getInstance().addExecuteProps(n, catalystProps, state, time); + CatalystManager::getInstance().addExecuteData(n, catalystProps.catalystInputName, state, time, m); + CatalystManager::getInstance().addExecuteData(n, m1Channel, state + 1, time + 1, m1); + CatalystManager::getInstance().addExecuteData(n, m2Channel, state + 2, time + 2, m2); + checkExecuteProps(n, catalystProps, state, time); + checkExecuteData(n, catalystProps.catalystInputName, state, time, m); + checkExecuteData(n, m1Channel, state + 1, time + 1, m1); + checkExecuteData(n, m2Channel, state + 2, time + 2, m2); +} diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_StructuredBlockTest.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_StructuredBlockTest.C new file mode 100644 index 0000000000..c124e995df --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_StructuredBlockTest.C @@ -0,0 +1,41 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include + +TEST_F(Iocatalyst_DatabaseIOTest, WriteOneStructuredBlockWith8Cells) +{ + Iocatalyst::BlockMesh bm; + setBlockMeshSize(2, 2, 2); + addBlockMesh(bm); + runStructuredTest("test_sb_1_cells_8"); +} + +TEST_F(Iocatalyst_DatabaseIOTest, WriteOneStructuredBlockWith200Cells) +{ + Iocatalyst::BlockMesh bm; + setBlockMeshSize(10, 10, 2); + addBlockMesh(bm); + runStructuredTest("test_sb_1_cells_200"); +} + +TEST_F(Iocatalyst_DatabaseIOTest, WriteThreeStructuredBlocksWith835Cells) +{ + Iocatalyst::BlockMesh bmOne; + setBlockMeshSize(5, 15, 3); + addBlockMesh(bmOne); + + Iocatalyst::BlockMesh bmTwo; + setBlockMeshSize(8, 14, 4); + setOrigin(5, 0, 0); + addBlockMesh(bmTwo); + + Iocatalyst::BlockMesh bmThree; + setBlockMeshSize(3, 6, 9); + setOrigin(13, 0, 0); + addBlockMesh(bmThree); + runStructuredTest("test_sb_3_cells_835"); +} \ No newline at end of file diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_TestDriverMain.C b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_TestDriverMain.C new file mode 100644 index 0000000000..7d0e88549f --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/Iocatalyst_TestDriverMain.C @@ -0,0 +1,31 @@ +// Copyright(C) 1999-2020 National Technology & Engineering Solutions +// of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with +// NTESS, the U.S. Government retains certain rights in this software. +// +// See packages/seacas/LICENSE for details + +#include "iocatalyst_export.h" +#include +#include +#include + +#ifdef SEACAS_HAVE_MPI +#include +#endif + +int IOCATALYST_EXPORT main(int argc, char **argv) +{ +#ifdef SEACAS_HAVE_MPI + MPI_Init(&argc, &argv); +#endif + + Ioss::Init::Initializer io; + testing::InitGoogleTest(&argc, argv); + int errorCode = RUN_ALL_TESTS(); + +#ifdef SEACAS_HAVE_MPI + MPI_Finalize(); +#endif + + return errorCode; +} diff --git a/packages/seacas/libraries/ioss/src/catalyst_tests/cmake/Dependencies.cmake b/packages/seacas/libraries/ioss/src/catalyst_tests/cmake/Dependencies.cmake new file mode 100644 index 0000000000..3c9b774e59 --- /dev/null +++ b/packages/seacas/libraries/ioss/src/catalyst_tests/cmake/Dependencies.cmake @@ -0,0 +1,3 @@ +TRIBITS_PACKAGE_DEFINE_DEPENDENCIES( + LIB_OPTIONAL_TPLS GTest +) diff --git a/packages/seacas/libraries/ioss/src/main/test/can.ex2 b/packages/seacas/libraries/ioss/src/main/test/can.ex2 new file mode 100755 index 0000000000..53b3af0743 Binary files /dev/null and b/packages/seacas/libraries/ioss/src/main/test/can.ex2 differ