Line data Source code
1 : // Copyright 2024, UChicago Argonne, LLC
2 : // All Rights Reserved
3 : // Software Name: NEML2 -- the New Engineering material Model Library, version 2
4 : // By: Argonne National Laboratory
5 : // OPEN SOURCE LICENSE (MIT)
6 : //
7 : // Permission is hereby granted, free of charge, to any person obtaining a copy
8 : // of this software and associated documentation files (the "Software"), to deal
9 : // in the Software without restriction, including without limitation the rights
10 : // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 : // copies of the Software, and to permit persons to whom the Software is
12 : // furnished to do so, subject to the following conditions:
13 : //
14 : // The above copyright notice and this permission notice shall be included in
15 : // all copies or substantial portions of the Software.
16 : //
17 : // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 : // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 : // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 : // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 : // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 : // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 : // THE SOFTWARE.
24 :
25 : #include "hit/braceexpr.h"
26 :
27 : #include "neml2/base/HITParser.h"
28 : #include "neml2/base/Registry.h"
29 : #include "neml2/base/Factory.h"
30 : #include "neml2/base/TensorName.h"
31 : #include "neml2/base/Settings.h"
32 : #include "neml2/base/EnumSelection.h"
33 : #include "neml2/base/MultiEnumSelection.h"
34 : #include "neml2/base/LabeledAxisAccessor.h"
35 : #include "neml2/tensors/tensors.h"
36 : #include "neml2/misc/assertions.h"
37 : #include "neml2/misc/types.h"
38 :
39 : namespace neml2
40 : {
41 : InputFile
42 357 : HITParser::parse(const std::filesystem::path & filename, const std::string & additional_input) const
43 : {
44 : // Open and read the file
45 357 : std::ifstream file(filename);
46 357 : neml_assert(file.is_open(), "Unable to open file ", filename);
47 :
48 : // Read the file into a string
49 357 : std::stringstream buffer;
50 357 : buffer << file.rdbuf();
51 357 : std::string input = buffer.str();
52 :
53 : // Let HIT lex the string
54 357 : std::unique_ptr<hit::Node> root(hit::parse(filename, input));
55 357 : neml_assert(root.get(), "HIT failed to lex the input file: ", filename);
56 :
57 : // Handle additional input (they could be coming from cli args)
58 357 : std::unique_ptr<hit::Node> cli_root(hit::parse("cliargs", additional_input));
59 357 : hit::merge(cli_root.get(), root.get());
60 :
61 : // Preevaluate the input
62 357 : hit::BraceExpander expander;
63 357 : hit::EnvEvaler env;
64 357 : hit::RawEvaler raw;
65 714 : expander.registerEvaler("env", env);
66 357 : expander.registerEvaler("raw", raw);
67 357 : root->walk(&expander);
68 :
69 711 : return parse(root.get());
70 378 : }
71 :
72 : InputFile
73 357 : HITParser::parse(hit::Node * root) const
74 : {
75 : // Extract global settings
76 357 : OptionSet settings = Settings::expected_options();
77 1071 : if (auto * const node = root->find("Settings"))
78 12 : extract_options(node, settings);
79 :
80 : // Loop over each known section and extract options for each object
81 357 : InputFile inp(settings);
82 2487 : for (const auto & section : Parser::sections)
83 : {
84 2133 : auto * section_node = root->find(section);
85 2133 : if (section_node)
86 : {
87 701 : auto objects = section_node->children(hit::NodeType::Section);
88 4025 : for (auto * object : objects)
89 : {
90 3327 : auto options = extract_object_options(object, section_node);
91 3324 : inp[section][options.name()] = options;
92 3324 : }
93 701 : }
94 : }
95 :
96 708 : return inp;
97 360 : }
98 :
99 : OptionSet
100 3327 : HITParser::extract_object_options(hit::Node * object, hit::Node * section) const
101 : {
102 : // There is a special field reserved for object type
103 6654 : std::string type = object->param<std::string>("type");
104 : // Extract the options
105 3327 : auto options = Registry::info(type).expected_options;
106 3327 : extract_options(object, options);
107 :
108 : // Also fill in the metadata
109 3324 : options.name() = object->path();
110 3324 : options.type() = type;
111 3324 : options.path() = section->fullpath();
112 :
113 6648 : return options;
114 3330 : }
115 :
116 : void
117 3339 : HITParser::extract_options(hit::Node * object, OptionSet & options) const
118 : {
119 13989 : for (auto * node : object->children(hit::NodeType::Field))
120 10653 : if (node->path() != "type")
121 10662 : extract_option(node, options);
122 3336 : }
123 :
124 : // NOLINTBEGIN
125 : void
126 7326 : HITParser::extract_option(hit::Node * n, OptionSet & options) const
127 : {
128 : #define extract_option_base(ptype, method) \
129 : else if (option->type() == utils::demangle(typeid(ptype).name())) \
130 : neml_assert(method(dynamic_cast<Option<ptype> *>(option.get())->set(), n->strVal()), \
131 : utils::parse_failure_message<ptype>(n->strVal()))
132 :
133 : #define extract_option_t(ptype) \
134 : extract_option_base(ptype, utils::parse_<ptype>); \
135 : extract_option_base(std::vector<ptype>, utils::parse_vector_<ptype>); \
136 : extract_option_base(std::vector<std::vector<ptype>>, utils::parse_vector_vector_<ptype>)
137 :
138 : #define extract_option_tensor_t(ptype) extract_option_t(TensorName<ptype>)
139 :
140 7326 : if (n->type() == hit::NodeType::Field)
141 : {
142 7326 : bool found = false;
143 104616 : for (auto & [name, option] : options)
144 104616 : if (name == n->path())
145 : {
146 7326 : neml_assert(!option->suppressed(),
147 : "Option named '",
148 7326 : option->name(),
149 : "' is suppressed, and its value cannot be modified.");
150 :
151 7325 : found = true;
152 :
153 : if (false)
154 : ;
155 7325 : extract_option_t(TensorShape);
156 5831 : extract_option_t(bool);
157 5680 : extract_option_t(int);
158 5647 : extract_option_t(unsigned int);
159 5608 : extract_option_t(std::size_t);
160 5608 : extract_option_t(Size);
161 4758 : extract_option_t(double);
162 3537 : extract_option_t(std::string);
163 2562 : extract_option_t(VariableName);
164 1850 : extract_option_t(EnumSelection);
165 1825 : extract_option_t(MultiEnumSelection);
166 1805 : FOR_ALL_TENSORBASE(extract_option_tensor_t);
167 30 : extract_option_tensor_t(ATensor);
168 30 : extract_option_t(Device);
169 : // LCOV_EXCL_START
170 : else neml_assert(false, "Unsupported option type for option ", n->fullpath());
171 : // LCOV_EXCL_STOP
172 :
173 7323 : option->user_specified() = true;
174 :
175 7323 : break;
176 : }
177 7323 : neml_assert(found, "Unused option ", n->fullpath());
178 : }
179 7323 : }
180 : // NOLINTEND
181 : } // namespace neml2
|