From b152199d34ed0f65d3d8e06c8db2807f7f056b6f Mon Sep 17 00:00:00 2001 From: Daniel Schwen Date: Wed, 31 Mar 2021 10:49:29 -0600 Subject: [PATCH] Rewrite NEML stress material (#193) --- include/materials/NEMLStress.h | 73 +++++------- src/materials/NEMLStress.C | 197 ++++++++++++++++----------------- 2 files changed, 123 insertions(+), 147 deletions(-) diff --git a/include/materials/NEMLStress.h b/include/materials/NEMLStress.h index 41f71cc3b..e9088a40b 100644 --- a/include/materials/NEMLStress.h +++ b/include/materials/NEMLStress.h @@ -17,62 +17,49 @@ #include "NEMLStressBase.h" #include "neml_interface.h" +#include +#include +#include + /** * NEMLStress computes the stress using a constitutive model provided by the NEML library. - * Parameters for that model are defined in an xml file and optionally in the input file. + * Parameters for that model are defined in an XML file and optionally in the input file. */ - class NEMLStress : public NEMLStressBase { public: static InputParameters validParams(); NEMLStress(const InputParameters & parameters); -private: - /** - * Get values from the input file that will be substituted in for the nemlNames provided in the - *input file - * @param nemlNames variables names from input file - * @return vector containing the values that will be substituted in for the each nemlNames - **/ - std::vector constructNemlSubstitutionList(const std::vector & nemlNames) const; +protected: + /// list of {variable} names for substitution in the XML file + std::vector _neml_variable_iname; + + /// Vector of values to substitute in + std::vector _neml_variable_value; + + /// Number of {variables{ to substitute in the XML}} + const std::size_t _nvars; + + /// set of variables in the XML file + std::set _xml_vars; - /** - * Error checking: find strings in string list 1 that are not found in string list 2 - * @param strList1 - * @param strList2 - * @return return strings from strList1 not found in strList2 - **/ - std::string compareVectorsOfStrings(const std::vector & strList1, - const std::vector & strList2) const; + /// max number of numbered value parameters (neml_variable_value0, neml_variable_value1, ...) + static const std::size_t _nvars_max = 8; - /** - * Parse the xml file into a string - * @param fname xml file name to be read in - * @return string containing file contents - **/ - std::string loadFileIntoString(const FileName & fname) const; + /// NEML XML Input + std::string _xml; - /** - * Get a list of variable names specified in the xml file - * @param xmlStringForNeml string containing xml file - * @return list of the variable names found in the xml file. - **/ - std::vector listOfVariablesInXml(const std::string & xmlStringForNeml) const; + /// Find strings in set 1 that are not found in set 2 + std::vector setDifference(const std::set & set1, + const std::set & set2) const; - /** - * Check that all variable names in xml file are also in the input file and vice versa - * @param nemlNames variables names from input file - * @param xmlStringForNeml string containing the xml file - **/ - void errorCheckVariableNamesFromInputFile(const std::vector & nemlNames, - const std::string & xmlStringForNeml) const; + /// Build a set of variable names specified in the xml file + void findXMLVariables(); - /** - * Substitute values in for the variables names found in the string version of the xml file - * @param xmlStringForNeml string containing the xml file, returned version of this string has - *values substituted in for variables names - **/ + /// Check that all variable names in xml file are also in the input file and vice versa + void errorCheckXMLVariables() const; - void replaceXmlVariables(std::string & xmlStringForNeml) const; + /// Substitute values in for the variables names found in the string version of the xml file + void replaceXMLVariables(); }; diff --git a/src/materials/NEMLStress.C b/src/materials/NEMLStress.C index 3dd765f9c..f3afd0a27 100644 --- a/src/materials/NEMLStress.C +++ b/src/materials/NEMLStress.C @@ -13,10 +13,13 @@ /****************************************************************/ #ifdef NEML_ENABLED + #include #include +#include #include "NEMLStress.h" +#include "Conversion.h" registerMooseObject("BlackBearApp", NEMLStress); @@ -28,143 +31,129 @@ NEMLStress::validParams() params.addRequiredParam("database", "Path to NEML XML database."); params.addRequiredParam("model", "Model name in NEML database."); params.addParam>("neml_variable_iname", - "Names of NEML xml name/value pairs"); - - params.addParam("neml_variable_value0", - "NEML xml variable value for neml_variable_iname[0]"); - params.addParam("neml_variable_value1", - "NEML xml variable value for neml_variable_iname[1]"); - params.addParam("neml_variable_value2", - "NEML xml variable value for neml_variable_iname[2]"); - params.addParam("neml_variable_value3", - "NEML xml variable value for neml_variable_iname[3]"); - params.addParam("neml_variable_value4", - "NEML xml variable value for neml_variable_iname[4]"); - params.addParam("neml_variable_value5", - "NEML xml variable value for neml_variable_iname[5]"); - params.addParam("neml_variable_value6", - "NEML xml variable value for neml_variable_iname[6]"); - params.addParam("neml_variable_value7", - "NEML xml variable value for neml_variable_iname[7]"); - + "Names of NEML XML name/value pairs"); + params.addParam>("neml_variable_value", + "Corresponding NEML XML variable values"); + for (size_t i = 0; i < _nvars_max; ++i) + { + auto istr = Moose::stringify(i); + params.addParam("neml_variable_value" + istr, + "NEML XML variable value for neml_variable_iname[" + istr + "]"); + } return params; } -NEMLStress::NEMLStress(const InputParameters & parameters) : NEMLStressBase(parameters) -{ - FileName fname(getParam("database")); - std::string mname(getParam("model")); - - std::string xmlStringForNeml = loadFileIntoString(fname); - if (isParamValid("neml_variable_iname")) - replaceXmlVariables(xmlStringForNeml); - - _model = neml::parse_string_unique(xmlStringForNeml, mname); -} - -std::string -NEMLStress::compareVectorsOfStrings(const std::vector & strList1, - const std::vector & strList2) const +NEMLStress::NEMLStress(const InputParameters & parameters) + : NEMLStressBase(parameters), + _neml_variable_iname(getParam>("neml_variable_iname")), + _neml_variable_value(getParam>("neml_variable_value")), + _nvars(_neml_variable_iname.size()) { - std::string missingNames; - for (auto & str1 : strList1) + // fetch and check inames and values for {variable} replacement + bool value_vector = false; + if (!_neml_variable_value.empty()) { - bool found = false; - for (auto & str2 : strList2) - { - if (str1 == str2) - { - found = true; - break; - } - } - if (!found) - missingNames += str1 + " "; + if (_nvars != _neml_variable_value.size()) + paramError("neml_variable_value", + "If any values are specified the number must match the number of entries in " + "neml_variable_iname"); + value_vector = true; + } + else if (_nvars > _nvars_max) + paramError("neml_variable_iname", + "NEMLStressVariableInput can only have up to ", + _nvars_max, + " neml_variable_iname entries"); + + // We permit the numbered parameters to override the values vector. + _neml_variable_value.resize(_nvars); + for (std::size_t i = 0; i < _nvars; ++i) + { + std::string iname = "neml_variable_value" + std::to_string(i); + if (isParamValid(iname)) + _neml_variable_value[i] = getParam(iname); + else if (!value_vector) + mooseError("Expected parameter '", iname, "' but it was not provided."); } - return missingNames; -} -std::string -NEMLStress::loadFileIntoString(const FileName & fname) const -{ // check if the file exists and can be read + const auto fname = getParam("database"); MooseUtils::checkFileReadable(fname); - // laod file into string + // load file into string std::ifstream t(fname.c_str()); - std::string str((std::istreambuf_iterator(t)), std::istreambuf_iterator()); - return str; + _xml.assign((std::istreambuf_iterator(t)), std::istreambuf_iterator()); + + // replace {variables} in the XML file + findXMLVariables(); + errorCheckXMLVariables(); + replaceXMLVariables(); + + // build NEML model object + auto mname = getParam("model"); + _model = neml::parse_string_unique(_xml, mname); } std::vector -NEMLStress::listOfVariablesInXml(const std::string & xmlStringForNeml) const +NEMLStress::setDifference(const std::set & set1, + const std::set & set2) const { - std::vector xmlVariableNames; - size_t open = xmlStringForNeml.find("{"); - size_t close = xmlStringForNeml.find("}"); - while (open != std::string::npos) - { - xmlVariableNames.push_back(xmlStringForNeml.substr(open + 1, close - (open + 1))); - open = xmlStringForNeml.find("{", open + 1); - close = xmlStringForNeml.find("}", open); - } - return xmlVariableNames; + std::vector result(set1.size() + set2.size()); + auto it = std::set_difference(set1.begin(), set1.end(), set2.begin(), set2.end(), result.begin()); + return std::vector(result.begin(), it); } void -NEMLStress::errorCheckVariableNamesFromInputFile(const std::vector & nemlNames, - const std::string & xmlStringForNeml) const +NEMLStress::findXMLVariables() { - std::vector xmlNames = listOfVariablesInXml(xmlStringForNeml); - std::string extraNemlNames = compareVectorsOfStrings(nemlNames, xmlNames); - std::string extraXmlNames = compareVectorsOfStrings(xmlNames, nemlNames); - if (!extraNemlNames.empty() || !extraXmlNames.empty()) + auto open = _xml.find("{"); + auto close = _xml.find("}", open); + while (open != std::string::npos) { - mooseError( - std::string("Mismatched NEML variable names between xml and BlackBear input file.\n") + - " BlackBear input file variable names not found in NEML xml file: " + extraNemlNames + - "\n NEML xml file variable names not found in BlackBear input file: " + extraXmlNames); + _xml_vars.insert(_xml.substr(open + 1, close - (open + 1))); + open = _xml.find("{", open + 1); + close = _xml.find("}", open); } } void -NEMLStress::replaceXmlVariables(std::string & xmlStringForNeml) const +NEMLStress::errorCheckXMLVariables() const { - std::vector nemlNames = getParam>("neml_variable_iname"); - std::vector nemlValues = constructNemlSubstitutionList(nemlNames); - errorCheckVariableNamesFromInputFile(nemlNames, xmlStringForNeml); - - for (size_t i = 0; i < nemlNames.size(); ++i) - { - std::string varName = nemlNames[i]; - Real varValue = nemlValues[i]; - size_t posOfFirstCurlyBrace = xmlStringForNeml.find(varName) - 1; - size_t varLengthWithBothCurlyBraces = varName.length() + 2; - xmlStringForNeml.replace( - posOfFirstCurlyBrace, varLengthWithBothCurlyBraces, std::to_string(varValue)); - } + std::set inames(_neml_variable_iname.begin(), _neml_variable_iname.end()); + if (inames.size() != _nvars) + paramError("neml_variable_iname", "Duplicate variable names"); + + auto d1 = setDifference(inames, _xml_vars); + auto d2 = setDifference(_xml_vars, inames); + + if (!d1.empty()) + paramError("neml_variable_iname", + "Input file variable names not found in NEML xml file: ", + Moose::stringify(d1)); + if (!d2.empty()) + paramError("database", + "NEML xml file variable names not found in BlackBear input file: ", + Moose::stringify(d2)); } -std::vector -NEMLStress::constructNemlSubstitutionList(const std::vector & nemlNames) const +void +NEMLStress::replaceXMLVariables() { - std::vector nemlValues; - if (isParamValid("neml_variable_iname")) + for (std::size_t i = 0; i < _nvars; ++i) { - if (nemlNames.size() > 8) - mooseError("NEMLStressVariableInput can only have up to eight neml_variable_iname[0-7]"); + auto key = "{" + _neml_variable_iname[i] + "}"; + auto len = key.length(); + auto value = Moose::stringify(_neml_variable_value[i]); - for (size_t i = 0; i < nemlNames.size(); ++i) + // substitute all occurrences + while (true) { - std::string iname = "neml_variable_value" + std::to_string(i); - if (isParamValid(iname)) - nemlValues.push_back(getParam(iname)); - else - mooseError( - "NEMLStressVariableInput: incorrect name or number of neml_variable_value keywords."); + auto pos = _xml.find(key); + if (pos == std::string::npos) + break; + _xml.replace(pos, len, value); } } - return nemlValues; } #endif // NEML_ENABLED