From 898f6cd88f383f16a2fa08e3bc14dc562bebffd1 Mon Sep 17 00:00:00 2001 From: Wenqing Wang <wenqing.wang@ufz.de> Date: Thu, 25 Jan 2024 13:38:35 +0100 Subject: [PATCH] [ParameterLib] Added a creator for the coordinate system with implicit bases --- ParameterLib/CoordinateSystem.h | 37 +++-- ParameterLib/CreateCoordinateSystem.cpp | 191 ++++++++++++++++++++---- 2 files changed, 189 insertions(+), 39 deletions(-) diff --git a/ParameterLib/CoordinateSystem.h b/ParameterLib/CoordinateSystem.h index 556a07fb27a..7a1f688ceee 100644 --- a/ParameterLib/CoordinateSystem.h +++ b/ParameterLib/CoordinateSystem.h @@ -23,22 +23,33 @@ class SpatialPosition; namespace ParameterLib { +/** + * \brief A local coordinate system used for tensor transformations. + * + * It offers a simple way for input of anisotropic tensors w.r.t. a coordinate + * system. + * The basis vectors form a transformation matrix \f$R = (e_0, e_1, e_2)\f$. + * For a given anisotropic tensor \f$A\f$ parameter with the corresponding + * \ref ogs_file_param__prj__parameters__parameter__use_local_coordinate_system + * the tensor is rotated according to the formula: \f$A' = R\cdot A\cdot R^T\f$. + * + * For computations in transverse isotropic material models, we can create a + * coordinate system with only one base, where the last base is explicitly + * given. The other bases are set as implicit and computed from the given base + * as follows: + * - For a 2D coordinate system, the unit vector orthogonal to + * the given base is used as the first base, + * - For a 3D coordinate system, the given base vector, \c unit_direction, + * is set as the third base, \f${\vec e}_2\f$. An arbitrary unit vector + * orthogonal to \f${\vec e}_2\f$ is selected as the second base + * \f$e_1\f$, and the first base \f${\vec e}_0\f$ is calculated as + * \f${\vec e}_0 = {\vec e}_1 \times {\vec e}_2\f$. + */ struct CoordinateSystem final { /** - * It is used to create a coordinate system with only one base, where the - * last base is explicitly given. The other bases are set as implicit and - * computed from the given base as follows: - * - For a 2D coordinate system, the unit vector orthogonal to - * the given base is used as the first base, - * - For a 3D coordinate system, the given base vector, \c unit_direction, - * is set as the third base, \f${\vec e}_2\f$. An arbitrary unit vector - * orthogonal to \f${\vec e}_2\f$ is selected as the second base - * \f$e_1\f$, and the first base \f${\vec e}_0\f$ is calculated as - * \f${\vec e}_0 = {\vec e}_1 \times {\vec e}_2\f$. - * - * This type of coordinate system can be used for computations in transverse - * isotropic material models. + * It is used to create a local coordinate system with only one base, where + * the last base is explicitly given as \c unit_direction. * * @param unit_direction The specified unit direction. */ diff --git a/ParameterLib/CreateCoordinateSystem.cpp b/ParameterLib/CreateCoordinateSystem.cpp index 083867c49dc..83ff60a9c5a 100644 --- a/ParameterLib/CreateCoordinateSystem.cpp +++ b/ParameterLib/CreateCoordinateSystem.cpp @@ -11,6 +11,8 @@ #include "CreateCoordinateSystem.h" +#include <string_view> + #include "BaseLib/ConfigTree.h" #include "Parameter.h" #include "Utils.h" @@ -20,6 +22,123 @@ namespace ParameterLib struct ParameterBase; struct CoordinateSystem; +// Note: the function is used for parsing +// 1. base1 for the case of an implicit base0. +// 2. or base2. +Parameter<double> const* parseBase1OrBase2( + BaseLib::ConfigTree const& config, + std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters, + int const expected_component_number, + std::string_view const base_tag_name) +{ + auto const base_parameter_name = config.getValue<std::string>(); + auto const& basis_vector = ParameterLib::findParameter<double>( + base_parameter_name, parameters, 0 /* any dimension */); + + int const component_number = basis_vector.getNumberOfGlobalComponents(); + if (base_tag_name == "basis_vector_1" && component_number != 2) + { + OGS_FATAL( + "The case of implicit \"basis_vector_0\" and " + "explicit \"basis_vector_1\" is for a 2D coordinate system. The " + "parameter for \"basis_vector_1\", {:s}, must have " + "two components but it has {:d}. In addition, \"basis_vector_2\" " + "should not exist in this case.", + base_parameter_name, component_number); + } + + if (component_number != expected_component_number) + { + OGS_FATAL( + "The read parameter `{:s}' for tag {:s} has the wrong number of " + "components ({:d} instead of {:d}).", + base_parameter_name, base_tag_name, component_number, + expected_component_number); + } + + return &basis_vector; +} + +void checkThirdBaseExistanceFor2D(BaseLib::ConfigTree const& config) +{ + auto const base2_config = + //! \ogs_file_param{prj__local_coordinate_system__basis_vector_2} + config.getConfigSubtreeOptional("basis_vector_2"); + if (base2_config) + { + OGS_FATAL( + "The tag \"basis_vector_2\" is not needed for a 2D local " + "coordinate system."); + } +} + +void confirmThirdBaseExplicit(BaseLib::ConfigTree const& config) +{ + auto const implicit_base2 = + //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_2__implicit} + config.getConfigAttribute<bool>("implicit", false); + if (implicit_base2) + { + OGS_FATAL("basis_vector_2 must be explicit."); + } +} + +std::optional<ParameterLib::CoordinateSystem> +createCoordinateSystemWithImplicitBase( + BaseLib::ConfigTree const& config, + std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters) +{ + //! \ogs_file_param{prj__local_coordinate_system__basis_vector_1} + auto const& config_base1 = config.getConfigSubtree("basis_vector_1"); + + // Parse the second vectors. + auto const implicit_base1 = + //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_1__implicit} + config_base1.getConfigAttribute<bool>("implicit", false); + + if (!implicit_base1) + { + // For 2D problem. + // Only the following case is accepted: + // <basis_vector_0 implicit = false/> + // <basis_vector_1> [two-component parameter] </basis_vector_1>. + int const expected_component_number = 2; + auto const basis_vector_1 = + parseBase1OrBase2(config_base1, parameters, + expected_component_number, "basis_vector_1"); + + checkThirdBaseExistanceFor2D(config); + + return ParameterLib::CoordinateSystem(*basis_vector_1); + } + + // For 3D problem. + // Only the following case is accepted: + // <basis_vector_0 implicit = false/> + // <basis_vector_1 implicit = false>. + // <basis_vector_2> [three-component parameter] </basis_vector_2>. + + // Parse the third basis vector, e2, for the three dimensional system. + auto const config_base2 = + //! \ogs_file_param{prj__local_coordinate_system__basis_vector_2} + config.getConfigSubtreeOptional("basis_vector_2"); + if (!config_base2) + { + OGS_FATAL( + "Both \"basis_vector_0\" and \"basis_vector_1\" are implicit but " + "\"basis_vector_2\" does not exist. If 2D coordinate system is " + "considered, please change \"basis_vector_1\" to explicit. If 3D " + "coordinate system is considered, please add \"basis_vector_2\"."); + } + + confirmThirdBaseExplicit(*config_base2); + + int const expected_component_number = 3; + auto const basis_vector_2 = parseBase1OrBase2( + *config_base2, parameters, expected_component_number, "basis_vector_2"); + return ParameterLib::CoordinateSystem(*basis_vector_2); +} + std::optional<ParameterLib::CoordinateSystem> createCoordinateSystem( std::optional<BaseLib::ConfigTree> const& config, std::vector<std::unique_ptr<ParameterLib::ParameterBase>> const& parameters) @@ -29,51 +148,71 @@ std::optional<ParameterLib::CoordinateSystem> createCoordinateSystem( return {}; } - DBUG("Reading coordinate system configuration."); - // // Fetch the first basis vector; its length defines the dimension. // + //! \ogs_file_param{prj__local_coordinate_system__basis_vector_0} + auto const& config_base0 = config->getConfigSubtree("basis_vector_0"); + auto const implicit_base0 = + //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_0__implicit} + config_base0.getConfigAttribute<bool>("implicit", false); + + // base0 and base1 can be implicit. If base0 is implicit, check whether + // base1 is implicit. + // If base1 is explicit, create a 2D system if its components is 2 or quit + // if its components is not equal to 2. + // Otherwise, read base2, create a 3D system if its components is 3 or quit + // if its components is not equal to 3. + if (implicit_base0) + { + return createCoordinateSystemWithImplicitBase(*config, parameters); + } + + auto const base0_name = config_base0.getValue<std::string>(); auto const& basis_vector_0 = ParameterLib::findParameter<double>( - *config, - //! \ogs_file_param_special{prj__local_coordinate_system__basis_vector_0} - "basis_vector_0", parameters, 0 /* any dimension */); + base0_name, parameters, 0 /* any dimension */); int const dimension = basis_vector_0.getNumberOfGlobalComponents(); - // check dimension if (dimension != 2 && dimension != 3) { OGS_FATAL( "Basis vector parameter '{:s}' must have two or three components, " "but it has {:d}.", - basis_vector_0.name, dimension); + base0_name, dimension); } - // - // Fetch the second basis vector, which must be of the same dimension as the - // first one. - // - auto const& basis_vector_1 = ParameterLib::findParameter<double>( - *config, - //! \ogs_file_param_special{prj__local_coordinate_system__basis_vector_1} - "basis_vector_1", parameters, dimension); + // Fetch the second basis vector. + //! \ogs_file_param{prj__local_coordinate_system__basis_vector_1} + auto const& config_base1 = config->getConfigSubtree("basis_vector_1"); + auto const implicit_base1 = + //! \ogs_file_attr{prj__local_coordinate_system__basis_vector_1__implicit} + config_base1.getConfigAttribute<bool>("implicit", false); + if (implicit_base1) + { + OGS_FATAL( + "Since basis_vector_0 is explicitly defined, basis_vector_1" + " must be explicit as well."); + } + auto const base1_name = config_base1.getValue<std::string>(); + auto const& basis_vector_1 = + ParameterLib::findParameter<double>(base1_name, parameters, dimension); - // - // For two dimensions, we are done; construct coordinate system; - // if (dimension == 2) { + checkThirdBaseExistanceFor2D(*config); return ParameterLib::CoordinateSystem{basis_vector_0, basis_vector_1}; } - // - // Parse the third vector, for three dimensions. - // - auto const& basis_vector_2 = ParameterLib::findParameter<double>( - *config, - //! \ogs_file_param_special{prj__local_coordinate_system__basis_vector_2} - "basis_vector_2", parameters, dimension); + // Parse the third basis vector, e2, for the three dimensional system. + //! \ogs_file_param{prj__local_coordinate_system__basis_vector_2} + auto const& config_base2 = config->getConfigSubtree("basis_vector_2"); + confirmThirdBaseExplicit(config_base2); + + int const expected_component_number = 3; + auto const basis_vector_2 = parseBase1OrBase2( + config_base2, parameters, expected_component_number, "basis_vector_2"); + return ParameterLib::CoordinateSystem{basis_vector_0, basis_vector_1, - basis_vector_2}; + *basis_vector_2}; } } // namespace ParameterLib -- GitLab