42 parameters: list[tuple[str, str, bool]],
47 output_path.parent.mkdir(parents=
True, exist_ok=
True)
49 parameter_replacements = {
50 constructor_name: member_name
for member_name, constructor_name, _
in parameters
52 constitutive_law_symbols = {
54 for symbol
in constitutive_law.free_symbols
55 if str(symbol)
not in parameter_replacements
58 raise ValueError(
"Constitutive law must define at least one variable")
59 if any(name
not in constitutive_law_symbols
for name
in variables):
60 raise ValueError(
"Constitutive law variables must match symbolic variables")
62 state_variable_name = variables[-1]
63 state_variable_symbol = constitutive_law_symbols[state_variable_name]
64 constitutive_law_replacements = dict(parameter_replacements)
65 output_symbol = symbols(output_variable)
66 inverse_solution = solve(
67 output_symbol - constitutive_law, state_variable_symbol, dict=
True
69 if not inverse_solution:
70 raise ValueError(
"Unable to invert constitutive law")
71 inverse_expression = inverse_solution[0][state_variable_symbol]
72 forward_value_expression = diff(constitutive_law, state_variable_symbol)
73 inverse_value_expression = diff(inverse_expression, output_symbol)
74 inverse_replacements = dict(parameter_replacements)
76 parameter_members =
"\n".join(
77 f
" {'const ' if is_const else ''}double {member_name};"
78 for member_name, _, is_const
in parameters
80 constructor_signature =
",\n ".join(
81 f
"double {constructor_name}_" for _, constructor_name, _
in parameters
83 constructor_initializers =
", ".join(
84 f
"{member_name}({constructor_name}_)"
85 for member_name, constructor_name, _
in parameters
87 forward_arguments =
", ".join(f
"double {name}" for name
in variables)
88 inverse_output_name = state_variable_name
89 inverse_arguments =
", ".join(
91 *[f
"double {name}" for name
in variables
if name != inverse_output_name],
92 f
"double {output_variable}",
96 output_path.write_text(
98// SPDX-FileCopyrightText: 2026 Baptiste Legouix
99// SPDX-License-Identifier: AGPL-3.0-or-later
103#include <Kokkos_Core.hpp>
105namespace {namespace} {{
112 constexpr explicit {class_name}(
113 {constructor_signature})
114 : {constructor_initializers}
118 KOKKOS_FUNCTION constexpr double value({forward_arguments}) const
120 return {_render_expression(forward_value_expression, state_variable_symbol, inverse_output_name, constitutive_law_replacements)};
123 KOKKOS_FUNCTION constexpr double jacobian({forward_arguments}) const
125 return value({", ".join(variables)});
128 KOKKOS_FUNCTION constexpr double operator()({forward_arguments}) const
130 return {_render_expression(constitutive_law, state_variable_symbol, inverse_output_name, constitutive_law_replacements)};
133 KOKKOS_FUNCTION constexpr double inverse_value({inverse_arguments}) const
135 return {_render_expression(inverse_value_expression, output_symbol, output_variable, inverse_replacements)};
138 KOKKOS_FUNCTION constexpr double inverse({inverse_arguments}) const
140 return {_render_expression(inverse_expression, output_symbol, output_variable, inverse_replacements)};
144}} // namespace {namespace}
150 functor_class, output_path: Path, *args, **kwargs
152 definition = functor_class.__call__(*args, **kwargs)
153 parameter_tuples = [(f
"m_{name}", name,
True)
for name
in definition.parameters]
155 output_path=output_path,
156 namespace=definition.namespace,
157 class_name=definition.class_name,
158 parameters=parameter_tuples,
159 variables=definition.variables,
160 output_variable=definition.output_variable,
161 constitutive_law=definition.constitutive_law,
None write_cpp_constitutive_law_header(Path output_path, str namespace, str class_name, list[tuple[str, str, bool]] parameters, list[str] variables, str output_variable, constitutive_law)