diff --git a/source/adios2/core/ADIOS.cpp b/source/adios2/core/ADIOS.cpp index 3e058c9f20..d87a3af9e7 100644 --- a/source/adios2/core/ADIOS.cpp +++ b/source/adios2/core/ADIOS.cpp @@ -130,11 +130,11 @@ ADIOS::ADIOS(const std::string configFile, helper::Comm comm, const std::string } if (helper::EndsWith(configFile, ".xml")) { - XMLInit(configFile); + m_ConfigFileContents = XMLInit(configFile); } else if (helper::EndsWith(configFile, ".yaml") || helper::EndsWith(configFile, ".yml")) { - YAMLInit(configFile); + m_ConfigFileContents = YAMLInit(configFile); } } #ifdef ADIOS2_HAVE_KOKKOS @@ -189,6 +189,20 @@ IO &ADIOS::DeclareIO(const std::string name, const ArrayOrdering ArrayOrder) IO &io = ioPair.first->second; io.SetDeclared(); io.SetArrayOrder(ArrayOrder); + + // Configure new IO objects with config file (if present) + if (!m_ConfigFile.empty() && !m_ConfigFileContents.empty()) + { + if (helper::EndsWith(m_ConfigFile, ".xml")) + { + XMLIOInit(m_ConfigFile, m_ConfigFileContents, io); + } + else if (helper::EndsWith(m_ConfigFile, ".yaml") || helper::EndsWith(m_ConfigFile, ".yml")) + { + YAMLInitIO(m_ConfigFile, m_ConfigFileContents, io); + } + } + return io; } @@ -286,14 +300,26 @@ void ADIOS::CheckOperator(const std::string name) const } } -void ADIOS::XMLInit(const std::string &configFileXML) +std::string ADIOS::XMLInit(const std::string &configFileXML) +{ + return helper::ParseConfigXML(*this, configFileXML, m_IOs, m_Operators); +} + +void ADIOS::XMLIOInit(const std::string &configFileXML, const std::string &configFileContents, + core::IO &io) +{ + helper::ParseConfigXMLIO(*this, configFileXML, configFileContents, io, m_Operators); +} + +std::string ADIOS::YAMLInit(const std::string &configFileYAML) { - helper::ParseConfigXML(*this, configFileXML, m_IOs, m_Operators); + return helper::ParseConfigYAML(*this, configFileYAML, m_IOs); } -void ADIOS::YAMLInit(const std::string &configFileYAML) +void ADIOS::YAMLInitIO(const std::string &configFileYAML, const std::string &configFileContents, + core::IO &io) { - helper::ParseConfigYAML(*this, configFileYAML, m_IOs); + helper::ParseConfigYAMLIO(*this, configFileYAML, configFileContents, io); } void ADIOS::Global_init_AWS_API() diff --git a/source/adios2/core/ADIOS.h b/source/adios2/core/ADIOS.h index 1e514ca051..87bb1c9a70 100644 --- a/source/adios2/core/ADIOS.h +++ b/source/adios2/core/ADIOS.h @@ -164,6 +164,7 @@ class ADIOS /** XML File to be read containing configuration information */ const std::string m_ConfigFile; + std::string m_ConfigFileContents; /** * @brief List of IO class objects defined from either ADIOS @@ -184,9 +185,15 @@ class ADIOS void CheckOperator(const std::string name) const; - void XMLInit(const std::string &configFileXML); + std::string XMLInit(const std::string &configFileXML); - void YAMLInit(const std::string &configFileYAML); + void XMLIOInit(const std::string &configFileXML, const std::string &configFileContents, + core::IO &io); + + std::string YAMLInit(const std::string &configFileYAML); + + void YAMLInitIO(const std::string &configFileYAML, const std::string &configFileContents, + core::IO &io); private: /* Global services that we want to initialize at most once and shutdown diff --git a/source/adios2/helper/adiosXML.cpp b/source/adios2/helper/adiosXML.cpp index a1595fcefb..a904c01ee5 100644 --- a/source/adios2/helper/adiosXML.cpp +++ b/source/adios2/helper/adiosXML.cpp @@ -13,14 +13,12 @@ /// \cond EXCLUDE_FROM_DOXYGEN #include //std::transform -#include // std::distance #include //std::invalid_argument /// \endcond #include "adios2/common/ADIOSTypes.h" #include "adios2/core/IO.h" #include "adios2/helper/adiosLog.h" -#include "adios2/helper/adiosString.h" #include "adios2/helper/adiosXMLUtil.h" #include @@ -30,162 +28,194 @@ namespace adios2 namespace helper { -void ParseConfigXML(core::ADIOS &adios, const std::string &configFileXML, - std::map &ios, - std::unordered_map> &operators) +std::string FileContents(core::ADIOS &adios, const std::string &configXML) { - const std::string hint("for config file " + configFileXML + " in call to ADIOS constructor"); + const std::string configFileContents(adios.GetComm().BroadcastFile( + configXML, "when parsing configXML file, in call to the ADIOS constructor")); - auto lf_FileContents = [&](const std::string &configXML) -> std::string { - const std::string fileContents(adios.GetComm().BroadcastFile( - configXML, "when parsing configXML file, in call to the ADIOS constructor")); + if (configFileContents.empty()) + { + helper::Throw("Helper", "AdiosXML", "ParseConfigXML", + "empty config xml file"); + } + return configFileContents; +} - if (fileContents.empty()) - { - helper::Throw("Helper", "AdiosXML", "ParseConfigXML", - "empty config xml file"); - } - return fileContents; - }; +void OperatorXML(core::ADIOS &adios, const pugi::xml_node &operatorNode, const std::string &hint) +{ + const std::unique_ptr name = + helper::XMLAttribute("name", operatorNode, hint); - auto lf_OperatorXML = [&](const pugi::xml_node &operatorNode) { - const std::unique_ptr name = - helper::XMLAttribute("name", operatorNode, hint); + const std::unique_ptr type = + helper::XMLAttribute("type", operatorNode, hint); - const std::unique_ptr type = - helper::XMLAttribute("type", operatorNode, hint); + std::string typeLowerCase = std::string(type->value()); + std::transform(typeLowerCase.begin(), typeLowerCase.end(), typeLowerCase.begin(), ::tolower); - std::string typeLowerCase = std::string(type->value()); - std::transform(typeLowerCase.begin(), typeLowerCase.end(), typeLowerCase.begin(), - ::tolower); + const Params parameters = helper::XMLGetParameters(operatorNode, hint); - const Params parameters = helper::XMLGetParameters(operatorNode, hint); + adios.DefineOperator(name->value(), typeLowerCase, parameters); +} - adios.DefineOperator(name->value(), typeLowerCase, parameters); - }; +void IOVariableXML(const pugi::xml_node &variableNode, core::IO &io, const std::string &hint, + std::unordered_map> &operators) +{ + const std::string variableName = + std::string(helper::XMLAttribute("name", variableNode, hint)->value()); - // node is the variable node - auto lf_IOVariableXML = [&](const pugi::xml_node &node, core::IO ¤tIO) { - const std::string variableName = - std::string(helper::XMLAttribute("name", node, hint)->value()); + for (const pugi::xml_node &operation : variableNode.children("operation")) + { + const std::unique_ptr opName = + helper::XMLAttribute("operator", operation, hint, false); - for (const pugi::xml_node &operation : node.children("operation")) + const std::unique_ptr opType = + helper::XMLAttribute("type", operation, hint, false); + + if (*opName && *opType) { - const std::unique_ptr opName = - helper::XMLAttribute("operator", operation, hint, false); + helper::Throw( + "Helper", "AdiosXML", "ParseConfigXML", + "operator (" + std::string(opName->value()) + ") and type (" + + std::string(opType->value()) + + ") attributes can't coexist in element " + "inside element"); + } - const std::unique_ptr opType = - helper::XMLAttribute("type", operation, hint, false); + if (!*opName && !*opType) + { + helper::Throw("Helper", "AdiosXML", "ParseConfigXML", + " element " + "inside element requires either operator " + "(existing) or type (supported) attribute"); + } - if (*opName && *opType) - { - helper::Throw( - "Helper", "AdiosXML", "ParseConfigXML", - "operator (" + std::string(opName->value()) + ") and type (" + - std::string(opType->value()) + - ") attributes can't coexist in element " - "inside element"); - } + std::string type; + Params params; - if (!*opName && !*opType) + if (*opName) + { + auto itOperator = operators.find(std::string(opName->value())); + if (itOperator == operators.end()) { - helper::Throw( - "Helper", "AdiosXML", "ParseConfigXML", - " element " - "inside element requires either operator " - "(existing) or type (supported) attribute"); + helper::Throw("Helper", "AdiosXML", "ParseConfigXML", + "operator " + std::string(opName->value()) + + " not previously defined, from variable " + + variableName + " inside io " + io.m_Name); } + type = itOperator->second.first; + params = itOperator->second.second; + } - std::string type; - Params params; + if (*opType) + { + type = std::string(opType->value()); + } - if (*opName) - { - auto itOperator = operators.find(std::string(opName->value())); - if (itOperator == operators.end()) - { - helper::Throw( - "Helper", "AdiosXML", "ParseConfigXML", - "operator " + std::string(opName->value()) + - " not previously defined, from variable " + variableName + - " inside io " + currentIO.m_Name); - } - type = itOperator->second.first; - params = itOperator->second.second; - } + for (const auto &p : helper::XMLGetParameters(operation, hint)) + { + params[p.first] = p.second; + } - if (*opType) - { - type = std::string(opType->value()); - } + io.m_VarOpsPlaceholder[variableName].emplace_back(type, params); + } +} - for (const auto &p : helper::XMLGetParameters(operation, hint)) - { - params[p.first] = p.second; - } +void IOXML(core::ADIOS &adios, const pugi::xml_node &ioNode, core::IO &io, const std::string &hint, + std::unordered_map> &operators) +{ + // must be unique per io + const std::unique_ptr engine = + helper::XMLNode("engine", ioNode, hint, false, true); - currentIO.m_VarOpsPlaceholder[variableName].push_back({type, params}); - } - }; + if (*engine) + { + const std::unique_ptr type = + helper::XMLAttribute("type", *engine, hint); + io.SetEngine(type->value()); - auto lf_IOXML = [&](const pugi::xml_node &io) { - const std::unique_ptr ioName = helper::XMLAttribute("name", io, hint); + const Params parameters = helper::XMLGetParameters(*engine, hint); + io.SetParameters(parameters); + } - // Build the IO object - auto itCurrentIO = - ios.emplace(std::piecewise_construct, std::forward_as_tuple(ioName->value()), - std::forward_as_tuple(adios, ioName->value(), true, adios.m_HostLanguage)); - core::IO ¤tIO = itCurrentIO.first->second; + for (const pugi::xml_node &transport : ioNode.children("transport")) + { + const std::unique_ptr type = + helper::XMLAttribute("type", transport, hint); - // must be unique per io - const std::unique_ptr engine = - helper::XMLNode("engine", io, hint, false, true); + const Params parameters = helper::XMLGetParameters(transport, hint); + io.AddTransport(type->value(), parameters); + } - if (*engine) - { - const std::unique_ptr type = - helper::XMLAttribute("type", *engine, hint); - currentIO.SetEngine(type->value()); + for (const pugi::xml_node &variable : ioNode.children("variable")) + { + IOVariableXML(variable, io, hint, operators); + } +} - const Params parameters = helper::XMLGetParameters(*engine, hint); - currentIO.SetParameters(parameters); - } +void ParseConfigXMLIO(core::ADIOS &adios, const std::string &configFileXML, + const std::string &configFileContents, core::IO &io, + std::unordered_map> &operators) +{ + const std::string hint("for config file " + configFileXML + " in call to ADIOS constructor"); - for (const pugi::xml_node &transport : io.children("transport")) - { - const std::unique_ptr type = - helper::XMLAttribute("type", transport, hint); + // the following copy is needed because pugi::xml_document modifies configFileContents + const std::string configFileContentsCopy = configFileContents; + const std::unique_ptr document = + helper::XMLDocument(configFileContentsCopy, hint); - const Params parameters = helper::XMLGetParameters(transport, hint); - currentIO.AddTransport(type->value(), parameters); - } + // must be unique + const std::unique_ptr config = + helper::XMLNode("adios-config", *document, hint, true); - for (const pugi::xml_node &variable : io.children("variable")) + for (const pugi::xml_node &ioNode : config->children("io")) + { + const std::unique_ptr ioName = + helper::XMLAttribute("name", ioNode, hint); + if (io.m_Name == ioName->value()) { - lf_IOVariableXML(variable, currentIO); + IOXML(adios, ioNode, io, hint, operators); + return; } - }; + } +} - // BODY OF FUNCTION - const std::string fileContents = lf_FileContents(configFileXML); - const std::unique_ptr document = helper::XMLDocument(fileContents, hint); +std::string +ParseConfigXML(core::ADIOS &adios, const std::string &configFileXML, + std::map &ios, + std::unordered_map> &operators) +{ + const std::string hint("for config file " + configFileXML + " in call to ADIOS constructor"); + + const std::string configFileContents = FileContents(adios, configFileXML); + // the following copy is needed because pugi::xml_document modifies configFileContents + const std::string configFileContentsCopy = configFileContents; + const std::unique_ptr document = + helper::XMLDocument(configFileContentsCopy, hint); // must be unique const std::unique_ptr config = helper::XMLNode("adios-config", *document, hint, true); - for (const pugi::xml_node &op : config->children("operator")) + for (const pugi::xml_node &opNode : config->children("operator")) { - lf_OperatorXML(op); + OperatorXML(adios, opNode, hint); } - for (const pugi::xml_node &io : config->children("io")) + for (const pugi::xml_node &ioNode : config->children("io")) { - lf_IOXML(io); + const std::unique_ptr ioName = + helper::XMLAttribute("name", ioNode, hint); + // Build the IO object + auto itCurrentIO = + ios.emplace(std::piecewise_construct, std::forward_as_tuple(ioName->value()), + std::forward_as_tuple(adios, ioName->value(), true, adios.m_HostLanguage)); + core::IO ¤tIO = itCurrentIO.first->second; + IOXML(adios, ioNode, currentIO, hint, operators); } + return configFileContents; } } // end namespace helper diff --git a/source/adios2/helper/adiosXML.h b/source/adios2/helper/adiosXML.h index 2c7aff26fe..6385aecfa5 100644 --- a/source/adios2/helper/adiosXML.h +++ b/source/adios2/helper/adiosXML.h @@ -26,9 +26,14 @@ namespace adios2 namespace helper { -void ParseConfigXML(core::ADIOS &adios, const std::string &configFile, - std::map &ios, - std::unordered_map> &operators); +void ParseConfigXMLIO(core::ADIOS &adios, const std::string &configFileXML, + const std::string &configFileContents, core::IO &io, + std::unordered_map> &operators); + +std::string +ParseConfigXML(core::ADIOS &adios, const std::string &configFile, + std::map &ios, + std::unordered_map> &operators); } // end namespace helper } // end namespace adios2 diff --git a/source/adios2/helper/adiosYAML.cpp b/source/adios2/helper/adiosYAML.cpp index a12d8f9d0c..ec835ce26c 100644 --- a/source/adios2/helper/adiosYAML.cpp +++ b/source/adios2/helper/adiosYAML.cpp @@ -63,102 +63,134 @@ Params YAMLNodeMapToParams(const YAML::Node &node, const std::string &hint) return parameters; } +constexpr bool isMandatory = true; +constexpr bool isNotMandatory = false; } // end empty namespace -void ParseConfigYAML(core::ADIOS &adios, const std::string &configFileYAML, - std::map &ios) +void IOVariableYAML(const YAML::Node &variableMap, core::IO ¤tIO, const std::string &hint) { - const std::string hint = - "when parsing config file " + configFileYAML + " in call to ADIOS constructor"; + const YAML::Node &variableNameScalar = + YAMLNode("Variable", variableMap, hint, isMandatory, YAML::NodeType::Scalar); + const std::string variableName = variableNameScalar.as(); - constexpr bool isMandatory = true; - constexpr bool isNotMandatory = false; + const YAML::Node operationsSequence = + YAMLNode("Operations", variableMap, hint, isNotMandatory, YAML::NodeType::Sequence); - auto lf_IOVariableYAML = [&](const YAML::Node &variableMap, core::IO ¤tIO) { - const YAML::Node &variableNameScalar = - YAMLNode("Variable", variableMap, hint, isMandatory, YAML::NodeType::Scalar); - const std::string variableName = variableNameScalar.as(); - - const YAML::Node operationsSequence = - YAMLNode("Operations", variableMap, hint, isNotMandatory, YAML::NodeType::Sequence); + if (operationsSequence) + { + // loop through each transport node + const std::string errorMessage = + " in operations node from variable " + variableName + ", " + hint; - if (operationsSequence) + for (auto it = operationsSequence.begin(); it != operationsSequence.end(); ++it) { - // loop through each transport node - const std::string errorMessage = - " in operations node from variable " + variableName + ", " + hint; + const YAML::Node typeScalar = + YAMLNode("Type", *it, errorMessage, isMandatory, YAML::NodeType::Scalar); - for (auto it = operationsSequence.begin(); it != operationsSequence.end(); ++it) - { - const YAML::Node typeScalar = - YAMLNode("Type", *it, errorMessage, isMandatory, YAML::NodeType::Scalar); - - Params parameters = YAMLNodeMapToParams(*it, hint); - const std::string operatorType = EraseKey("Type", parameters); + Params parameters = YAMLNodeMapToParams(*it, hint); + const std::string operatorType = EraseKey("Type", parameters); - currentIO.m_VarOpsPlaceholder[variableName].push_back({operatorType, parameters}); - } + currentIO.m_VarOpsPlaceholder[variableName].emplace_back(operatorType, parameters); } - }; - - auto lf_IOYAML = [&](const std::string &ioName, const YAML::Node &ioMap) { - // Build the IO object - auto itCurrentIO = - ios.emplace(std::piecewise_construct, std::forward_as_tuple(ioName), - std::forward_as_tuple(adios, ioName, true, adios.m_HostLanguage)); - core::IO ¤tIO = itCurrentIO.first->second; + } +} - // Engine parameters - const YAML::Node engineMap = YAMLNode("Engine", ioMap, hint, false, YAML::NodeType::Map); +void IOYAML(core::ADIOS &adios, const YAML::Node &ioMap, core::IO &io, const std::string &hint) +{ + // Engine parameters + const YAML::Node engineMap = YAMLNode("Engine", ioMap, hint, false, YAML::NodeType::Map); - if (engineMap) + if (engineMap) + { + Params parameters = YAMLNodeMapToParams(engineMap, hint); + auto itType = parameters.find("Type"); + if (itType != parameters.end()) { - Params parameters = YAMLNodeMapToParams(engineMap, hint); - auto itType = parameters.find("Type"); - if (itType != parameters.end()) - { - const std::string type = EraseKey("Type", parameters); - currentIO.SetEngine(type); - } - currentIO.SetParameters(parameters); + const std::string type = EraseKey("Type", parameters); + io.SetEngine(type); } + io.SetParameters(parameters); + } - // Variables - const YAML::Node variablesSequence = - YAMLNode("Variables", ioMap, hint, false, YAML::NodeType::Sequence); + // Variables + const YAML::Node variablesSequence = + YAMLNode("Variables", ioMap, hint, false, YAML::NodeType::Sequence); - if (variablesSequence) + if (variablesSequence) + { + // loop through each variable node + for (const YAML::Node &variableMap : variablesSequence) { - // loop through each variable node - for (const YAML::Node &variableMap : variablesSequence) - { - lf_IOVariableYAML(variableMap, currentIO); - } + IOVariableYAML(variableMap, io, hint); } + } - // Transports - const YAML::Node transportsSequence = - YAMLNode("Transports", ioMap, hint, false, YAML::NodeType::Sequence); + // Transports + const YAML::Node transportsSequence = + YAMLNode("Transports", ioMap, hint, false, YAML::NodeType::Sequence); - if (transportsSequence) + if (transportsSequence) + { + // loop through each transport node + for (auto it = transportsSequence.begin(); it != transportsSequence.end(); ++it) { - // loop through each transport node - for (auto it = transportsSequence.begin(); it != transportsSequence.end(); ++it) - { - YAMLNode("Type", *it, " in transport node " + hint, isMandatory, - YAML::NodeType::Scalar); + YAMLNode("Type", *it, " in transport node " + hint, isMandatory, + YAML::NodeType::Scalar); + + Params parameters = YAMLNodeMapToParams(*it, hint); + const std::string type = EraseKey("Type", parameters); + + io.AddTransport(type, parameters); + } + } +} + +void ParseConfigYAMLIO(core::ADIOS &adios, const std::string &configFileYAML, + const std::string &configFileContents, core::IO &io) +{ + const std::string hint = + "when parsing config file " + configFileYAML + " in call to ADIOS constructor"; + + // the following copy is needed because YAML::Load modifies configFileContents + const std::string configFileContentsCopy = configFileContents; + const YAML::Node document = YAML::Load(configFileContentsCopy); - Params parameters = YAMLNodeMapToParams(*it, hint); - const std::string type = EraseKey("Type", parameters); + if (!document) + { + helper::Throw( + "Helper", "adiosYAML", "ParseConfigYAML", + "parser error in file " + configFileYAML + + " invalid format check with any YAML editor if format is " + "ill-formed, " + + hint); + } - currentIO.AddTransport(type, parameters); + for (auto itNode = document.begin(); itNode != document.end(); ++itNode) + { + const YAML::Node ioScalar = + YAMLNode("IO", *itNode, hint, isNotMandatory, YAML::NodeType::Scalar); + if (ioScalar) + { + const std::string ioName = ioScalar.as(); + if (ioName == io.m_Name) + { + IOYAML(adios, *itNode, io, hint); + return; } } - }; + } +} + +std::string ParseConfigYAML(core::ADIOS &adios, const std::string &configFileYAML, + std::map &ios) +{ + const std::string hint = + "when parsing config file " + configFileYAML + " in call to ADIOS constructor"; - // BODY OF FUNCTION STARTS HERE - const std::string fileContents = adios.GetComm().BroadcastFile(configFileYAML, hint); - const YAML::Node document = YAML::Load(fileContents); + const std::string configFileContents = adios.GetComm().BroadcastFile(configFileYAML, hint); + // the following copy is needed because YAML::Load modifies configFileContents + const std::string configFileContentsCopy = configFileContents; + const YAML::Node document = YAML::Load(configFileContentsCopy); if (!document) { @@ -177,9 +209,15 @@ void ParseConfigYAML(core::ADIOS &adios, const std::string &configFileYAML, if (ioScalar) { const std::string ioName = ioScalar.as(); - lf_IOYAML(ioName, *itNode); + // Build the IO object + auto itCurrentIO = + ios.emplace(std::piecewise_construct, std::forward_as_tuple(ioName), + std::forward_as_tuple(adios, ioName, true, adios.m_HostLanguage)); + core::IO ¤tIO = itCurrentIO.first->second; + IOYAML(adios, *itNode, currentIO, hint); } } + return configFileContents; } } // end namespace helper diff --git a/source/adios2/helper/adiosYAML.h b/source/adios2/helper/adiosYAML.h index 6d8bfa12a1..8014d0cf06 100644 --- a/source/adios2/helper/adiosYAML.h +++ b/source/adios2/helper/adiosYAML.h @@ -25,9 +25,11 @@ namespace adios2 { namespace helper { +void ParseConfigYAMLIO(core::ADIOS &adios, const std::string &configFileYAML, + const std::string &configFileContents, core::IO &io); -void ParseConfigYAML(core::ADIOS &adios, const std::string &configFile, - std::map &ios); +std::string ParseConfigYAML(core::ADIOS &adios, const std::string &configFileYAML, + std::map &ios); } // end namespace helper } // end namespace adios2 diff --git a/testing/adios2/xml/TestXMLConfig.cpp b/testing/adios2/xml/TestXMLConfig.cpp index 93852393d4..1fd890ab5d 100644 --- a/testing/adios2/xml/TestXMLConfig.cpp +++ b/testing/adios2/xml/TestXMLConfig.cpp @@ -117,6 +117,32 @@ TEST_F(XMLConfigTest, OpNoneException) #endif } +TEST_F(XMLConfigTest, RemoveIO) +{ + const std::string configFile(configDir + std::string(&adios2::PathSeparator, 1) + + "configRemoveIO.xml"); + +#if ADIOS2_USE_MPI + adios2::ADIOS adios(configFile, MPI_COMM_WORLD); +#else + adios2::ADIOS adios(configFile); +#endif + + adios2::IO io; + adios2::Engine engine; + + std::string io_name_ = "checkpoint"; + for (int c = 0; c < 3; c++) + { + io = adios.DeclareIO(io_name_); + std::string filename = "test.bp"; + engine = io.Open(filename, adios2::Mode::Write); + EXPECT_TRUE(io.EngineType() == "BP4"); + engine.Close(); + adios.RemoveIO(io_name_); + } +} + int main(int argc, char **argv) { #if ADIOS2_USE_MPI diff --git a/testing/adios2/xml/configRemoveIO.xml b/testing/adios2/xml/configRemoveIO.xml new file mode 100644 index 0000000000..3c9a8ef22a --- /dev/null +++ b/testing/adios2/xml/configRemoveIO.xml @@ -0,0 +1,8 @@ + + + + + + + +