Skip to content

Commit

Permalink
Merge pull request #431 from tjotaha/catalyst_api_2_structured_blocks
Browse files Browse the repository at this point in the history
Catalyst API 2 IOSS Full Implementation
  • Loading branch information
gsjaardema authored Feb 2, 2024
2 parents 24c9b2c + 4b3cdfd commit 5fcd051
Show file tree
Hide file tree
Showing 26 changed files with 4,769 additions and 263 deletions.
1 change: 1 addition & 0 deletions cmake-config
Original file line number Diff line number Diff line change
Expand Up @@ -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}

Expand Down
3 changes: 3 additions & 0 deletions packages/seacas/libraries/ioss/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
8 changes: 1 addition & 7 deletions packages/seacas/libraries/ioss/src/catalyst/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")

#IF (BUILD_TESTING)
# ENABLE_TESTING()
#ENDIF (BUILD_TESTING)
#
#TRIBITS_ADD_TEST_DIRECTORIES(utest)
Original file line number Diff line number Diff line change
@@ -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 <Ioss_Utils.h>
#include <fstream>
#include <iostream>
#include <time.h>
#include <catalyst/Iocatalyst_CatalystLogging.h>

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<std::string> CatalystLogging::writeToLogFile()
{
std::vector<std::string> 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<std::string> headers = getLogFileHeaders();
if (isLogFileEmpty()) {
writeVectorWithDelimeter(logFile, headers, getDelimeter());
}
logLine = getLogOutputFromProps(headers);
writeVectorWithDelimeter(logFile, logLine, getDelimeter());
logFile.close();
}
}
return logLine;
}

std::vector<std::string> CatalystLogging::getLogFileHeaders()
{
std::vector<std::string> 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<std::string> &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<std::vector<std::string>> CatalystLogging::readLogFile()
{
return readLogFile(getLogFilePath());
}

std::vector<std::vector<std::string>> CatalystLogging::readLogFile(const std::string &logFilePath)
{
std::vector<std::vector<std::string>> 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<std::string> CatalystLogging::splitStringWithDelimeter(const std::string &input,
char delimeter)
{
std::string buffer = "";
std::vector<std::string> 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<std::string> CatalystLogging::getLogOutputFromProps(std::vector<std::string> &headers)
{
std::vector<std::string> 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
Original file line number Diff line number Diff line change
@@ -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 <Ioss_CodeTypes.h>
#include <Ioss_PropertyManager.h>
#include <string>
#include <vector>

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<std::string> getLogFileHeaders();
std::vector<std::string> writeToLogFile();
std::vector<std::vector<std::string>> readLogFile();
static std::vector<std::vector<std::string>> 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<std::string> &string_vector,
char delimeter);
static std::vector<std::string> splitStringWithDelimeter(const std::string &input,
char delimeter);
bool isLogFileEmpty();
std::vector<std::string> getLogOutputFromProps(std::vector<std::string> &headers);
};

} // namespace Iocatalyst

#endif
Loading

0 comments on commit 5fcd051

Please sign in to comment.