opm-simulators/opm/simulators/utils/DamarisKeywords.cpp

262 lines
9.7 KiB
C++

/*
Copyright 2021 Equinor.
Copyright 2023 Inria.
This file is part of the Open Porous Media project (OPM).
OPM is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OPM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <opm/simulators/utils/DamarisKeywords.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/common/OpmLog/OpmLog.hpp>
#include <Damaris.h>
#include <damaris/env/Environment.hpp>
#include <fmt/format.h>
#include <fstream>
#include <map>
#include <random>
#include <stdexcept>
#include <string>
/**
Below are the Damaris Keywords supported by Damaris to be filled
in the built-in XML file.
The entries in the map below will be filled by the corresponding
Damaris Keywords.
The command line arguments are defined in opm/simulators/flow/DamarisWriter.hpp
and defaults are set in opm/simulators/flow/FlowProblemProperties.hpp
*/
namespace Opm::DamarisOutput
{
bool FileExists(const std::string& filename_in,
const Parallel::Communication& comm)
{
// From c++17 : std::filesystem::exists(filename_in);
int retint = 1;
std::ifstream filestr;
bool file_exists = false;
if ((filename_in.length() == 0) || (filename_in == "#") ) {
return file_exists;
}
if (comm.rank() == 0) {
filestr.open(filename_in);
if(filestr.fail()) {
retint = 0;
} else {
retint = 1;
filestr.close();
}
}
comm.broadcast(&retint, 1, 0);
if (retint == 1) {
file_exists = true;
} else {
file_exists = false;
}
return (file_exists);
}
void DamarisSettings::SetRandString(void)
{
// rand_value_str_ = damaris::Environment::GetMagicNumber(comm); // requires Damaris >= v1.9.2
// We will create a random value.
// Seed with a real random value, if available
std::random_device r;
// Choose a random number between 0 and MAX_INT
std::default_random_engine e1(r());
std::uniform_int_distribution<int> uniform_dist(0, std::numeric_limits<int>::max());
int rand_int = uniform_dist(e1);
rand_value_str_ = std::to_string(rand_int) ;
}
std::map<std::string, std::string>
DamarisSettings::getKeywords([[maybe_unused]] const Parallel::Communication& comm,
const std::string& OutputDir)
{
SetRandString() ; // sets rand_value_str_ used for naming things that might need a unique name
std::string saveToHDF5_str("MyStore");
if (! saveToDamarisHDF5_ ){
saveToHDF5_str = "#";
}
// These strings are used to comment out an XML element if it is not reqired
std::string disablePythonXMLstart("!--");
std::string disablePythonXMLfin("--");
std::string disableParaviewXMLstart("!--");
std::string disableParaviewXMLfin("--");
std::string publishToPython_str("#"); // to be changed to the name of the PyScript XML element
// Test if input Python file exists and set the name of the script for <variable ... script="" > )XML elements
if (pythonFilename_ != ""){
if (FileExists(pythonFilename_, comm)) {
publishToPython_str="PythonScript"; // the name of the PyScript XML element
disablePythonXMLstart.clear();
disablePythonXMLfin.clear();
} else {
pythonFilename_.clear(); // set to empty if it does not exist
disablePythonXMLstart = std::string("!--");
disablePythonXMLfin = std::string("--");
}
}
// Test if input Paraview Python file exists
if (paraviewPythonFilename_ != ""){
if (FileExists(paraviewPythonFilename_, comm)) {
disableParaviewXMLstart.clear();
disableParaviewXMLfin.clear();
} else {
paraviewPythonFilename_.clear(); // set to empty if it does not exist
disableParaviewXMLstart = std::string("!--");
disableParaviewXMLfin = std::string("--");
}
}
// Flag error if both scripts are enabled
if ((pythonFilename_.size() > 0) && (paraviewPythonFilename_.size() > 0) )
{
// A work around of this issue is to remove the Paraview mpi4py library (use print(inspect.getfile(mpi4py)))
// and then possibly not use mpi4py in the Paraview script code. OR try to install paraview mpi4py with headers.
// The Python script will issue: ERROR: Initialiazation via BOOST_PYTHON_MODULE(server) failed at import_mpi4py()
OPM_THROW(std::runtime_error, "ERROR: Both the Python (--damaris-python-script command line argument) and Paraview Python "
"(--damaris-python-paraview-script command line argument) scripts are valid, however only one "
"type of analysis is supported in a single simulation (due to Paraview installing mpi4py library "
"locally and without header files). "
"Please choose one or the other method of analysis for now. Exiting." );
}
std::string saveMeshToHDF5_str("#");
if (saveMeshToHDF5_ == true) {
enableDamarisOutputCollective_ = false ;
saveMeshToHDF5_str = "MyStore" ;
}
std::string damarisOutputCollective_str;
if (enableDamarisOutputCollective_) {
damarisOutputCollective_str = "Collective";
} else {
damarisOutputCollective_str = "FilePerCore";
}
OpmLog::info(fmt::format("Opm::DamarisOutput::DamarisKeywords() : <option key=\"FileMode\"> {} </option> ",
damarisOutputCollective_str));
std::string simName_str;
// Check if simulation name was given on command line
// The simulation name is used as a prefix to name HDF5 files
if (damarisSimName_.empty()) {
simName_str = "opm-flow-" + rand_value_str_;
} else {
simName_str = damarisSimName_;
}
OpmLog::info(fmt::format("Opm::DamarisOutput::DamarisKeywords() : <simulation name={} ",
simName_str));
// A different shared memory buffer name is important if multiple simulations
// are running on the same node, as one simulation will remove the buffer when it exits,
// which will remove the buffer for other simulations.
std::string shmemName_str;
if ( shmemName_.empty()) {
shmemName_str = "opm-damaris-" + rand_value_str_;
} else {
shmemName_str = shmemName_ ;
}
std::string shmemSizeBytes_str;
if (shmemSizeBytes_ != 0) {
shmemSizeBytes_str = std::to_string(shmemSizeBytes_);
} else {
shmemSizeBytes_str = "536870912"; // 512 MB
}
OpmLog::info(fmt::format("Opm::DamarisOutput::DamarisKeywords() : <buffer name={} size={} ",
shmemName_str, shmemSizeBytes_str));
if ((nDamarisCores_ > 0) && (nDamarisNodes_ > 0))
{
nDamarisNodes_ = 0; // Default is to use Damaris Cores
}
std::string nDamarisCores_str;
if ( nDamarisCores_ != 0 ) {
nDamarisCores_str = std::to_string(nDamarisCores_);
} else {
nDamarisCores_str = "0";
}
std::string nDamarisNodes_str;
if ( nDamarisNodes_ != 0 ) {
nDamarisNodes_str = std::to_string(nDamarisNodes_);
} else {
nDamarisNodes_str = "0";
}
OpmLog::info(fmt::format("Opm::DamarisOutput::DamarisKeywords() : <dedicated cores={} nodes={} ",
nDamarisCores_str, nDamarisNodes_str));
std::string logLevel_str(damarisLogLevel_);
std::string logFlush_str("false");
if ((logLevel_str == "debug") || (logLevel_str == "trace") ) {
logFlush_str = "true";
}
OpmLog::info(fmt::format("Opm::DamarisOutput::DamarisKeywords() : <log FileName={}/damaris_log/{} Flush={} LogLevel={} ",
OutputDir, simName_str, logFlush_str, logLevel_str));
std::map<std::string, std::string> damaris_keywords = {
{"_SHMEM_BUFFER_BYTES_REGEX_", shmemSizeBytes_str},
{"_DC_REGEX_", nDamarisCores_str},
{"_DN_REGEX_", nDamarisNodes_str},
{"_File_Mode", damarisOutputCollective_str},
{"_MORE_VARIABLES_REGEX_", ""},
{"_PATH_REGEX_", OutputDir}, /* Do Not change the string "_PATH_REGEX_" as it is used to search for the output path */
{"_MYSTORE_OR_EMPTY_REGEX_", saveToHDF5_str},
{"_MYSTORE_MESH_OR_EMPTY_REGEX_", saveMeshToHDF5_str},
{"_PARAVIEW_PYTHON_SCRIPT_",paraviewPythonFilename_}, /* this has to be before _PYTHON_SCRIPT_ entry */
{"_PYTHON_SCRIPT_",pythonFilename_}, /* if a Python script is specified then assume that we want to publish the data to Python */
{"_PRESSURE_UNIT_","Pa"},
{"_MAKE_AVAILABLE_IN_PYTHON_",publishToPython_str}, /* must match <pyscript name="PythonScript" */
{"_SIM_NAME_",simName_str},
{"_SHMEM_NAME_",shmemName_str},
{"_LOG_LEVEL_",logLevel_str},
{"_LOG_FLUSH_",logFlush_str},
{"_DISABLEPYTHONSTART_",disablePythonXMLstart},
{"_DISABLEPYTHONFIN_",disablePythonXMLfin},
{"_DISABLEPARAVIEWSTART_",disableParaviewXMLstart},
{"_DISABLEPARAVIEWFIN_",disableParaviewXMLfin},
{"_DASK_SCHEDULER_FILE_",damarisDaskFile_},
};
return damaris_keywords;
}
} // namespace Opm::DamarisOutput