-
Notifications
You must be signed in to change notification settings - Fork 69
Fix normal pressure Neumann conditions on 2D solid lines #2210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ | |||||
| #include "4C_fem_general_cell_type_traits.hpp" | ||||||
| #include "4C_fem_general_element.hpp" | ||||||
| #include "4C_fem_general_element_integration.hpp" | ||||||
| #include "4C_fem_general_extract_values.hpp" | ||||||
| #include "4C_fem_general_utils_gausspoints.hpp" | ||||||
| #include "4C_fem_general_utils_local_connectivity_matrices.hpp" | ||||||
| #include "4C_global_data.hpp" | ||||||
|
|
@@ -21,6 +22,99 @@ | |||||
|
|
||||||
| FOUR_C_NAMESPACE_OPEN | ||||||
|
|
||||||
| namespace | ||||||
| { | ||||||
| template <Core::FE::CellType celltype> | ||||||
| void evaluate_normal_pressure(Core::Elements::Element& element, | ||||||
| const Core::FE::Discretization& discretization, const Core::Conditions::Condition& condition, | ||||||
| const std::vector<int>& dof_index_array, Core::LinAlg::SerialDenseVector& force, | ||||||
| Core::LinAlg::SerialDenseMatrix* load_linearization, const double total_time, | ||||||
| const double reference_thickness, const std::string& displacement_state) | ||||||
| { | ||||||
| constexpr int num_nodes = Core::FE::num_nodes(celltype); | ||||||
| const int num_dof_per_node = element.num_dof_per_node(*element.nodes()[0]); | ||||||
| const auto& onoff = condition.parameters().get<std::vector<int>>("ONOFF"); | ||||||
| const auto& values = condition.parameters().get<std::vector<double>>("VAL"); | ||||||
| const auto& function_ids = condition.parameters().get<std::vector<std::optional<int>>>("FUNCT"); | ||||||
| FOUR_C_ASSERT_ALWAYS(onoff.size() >= 2 && values.size() >= 2 && function_ids.size() >= 2, | ||||||
| "A two-dimensional pressure condition requires at least two entries in ONOFF, VAL, and " | ||||||
| "FUNCT."); | ||||||
| FOUR_C_ASSERT_ALWAYS( | ||||||
| onoff[0] == 1 && onoff[1] == 0, "Normal pressure must be activated on the first dof only."); | ||||||
|
|
||||||
| const auto displacement = discretization.get_state(displacement_state); | ||||||
| FOUR_C_ASSERT_ALWAYS( | ||||||
| displacement != nullptr, "Cannot get state vector '{}'.", displacement_state); | ||||||
| const std::vector<double> local_displacement = | ||||||
| Core::FE::extract_values(*displacement, dof_index_array); | ||||||
|
|
||||||
| Core::LinAlg::Matrix<num_nodes, 2> current_coordinates; | ||||||
| for (int node = 0; node < num_nodes; ++node) | ||||||
| for (int component = 0; component < 2; ++component) | ||||||
| current_coordinates(node, component) = | ||||||
| element.nodes()[node]->x()[component] + | ||||||
| local_displacement[node * num_dof_per_node + component]; | ||||||
|
|
||||||
| const auto integration = Core::FE::create_gauss_integration<celltype>( | ||||||
| Discret::Elements::get_gauss_rule_stiffness_matrix<celltype>()); | ||||||
| for (int gp = 0; gp < integration.num_points(); ++gp) | ||||||
| { | ||||||
| const auto xi = Core::Elements::evaluate_parameter_coordinate<celltype>(integration, gp); | ||||||
| Core::Elements::ElementNodes<celltype, 2> nodes{.coordinates = current_coordinates}; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could be moved out of the GP loop. |
||||||
| const auto shape = Core::Elements::evaluate_shape_functions_and_derivs<celltype>(xi, nodes); | ||||||
|
|
||||||
| Core::LinAlg::Matrix<2, 1> current_coordinate; | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, you could declare it out of the loop, and then update it via multiply_tn:
Suggested change
|
||||||
| current_coordinate.multiply_tn(current_coordinates, shape.values); | ||||||
| const double function_factor = | ||||||
| function_ids[0].has_value() && function_ids[0].value() > 0 | ||||||
| ? Global::Problem::instance() | ||||||
| ->function_by_id<Core::Utils::FunctionOfSpaceTime>(function_ids[0].value()) | ||||||
| .evaluate(current_coordinate.as_span(), total_time, 0) | ||||||
| : 1.0; | ||||||
|
|
||||||
| Discret::Elements::add_normal_pressure_load<celltype>(shape, current_coordinates, | ||||||
| values[0] * function_factor * integration.weight(gp), reference_thickness, | ||||||
| num_dof_per_node, force, load_linearization); | ||||||
| } | ||||||
| } | ||||||
| } // namespace | ||||||
|
|
||||||
| void Discret::Elements::evaluate_normal_pressure_by_element(Core::Elements::Element& element, | ||||||
| const Core::FE::Discretization& discretization, const Core::Conditions::Condition& condition, | ||||||
| const std::vector<int>& dof_index_array, Core::LinAlg::SerialDenseVector& force, | ||||||
| Core::LinAlg::SerialDenseMatrix* load_linearization, const double total_time, | ||||||
| const double reference_thickness) | ||||||
| { | ||||||
| const auto& type = condition.parameters().get<std::string>("TYPE"); | ||||||
| std::string displacement_state; | ||||||
| if (type == "pseudo_orthopressure") | ||||||
| { | ||||||
| displacement_state = "displacement"; | ||||||
| load_linearization = nullptr; | ||||||
| } | ||||||
| else if (type == "orthopressure") | ||||||
| { | ||||||
| FOUR_C_ASSERT_ALWAYS( | ||||||
| Global::Problem::instance()->structural_dynamic_params().get<bool>("LOADLIN"), | ||||||
| "If you use NEUMANN CONDITIONS with TYPE: \"orthopressure\" you need to set " | ||||||
| "'LOADLIN: true' in 'STRUCTURAL DYNAMIC'."); | ||||||
| displacement_state = "displacement new"; | ||||||
| } | ||||||
| else | ||||||
| { | ||||||
| FOUR_C_THROW("Expected a normal-pressure condition, got TYPE '{}'.", type); | ||||||
| } | ||||||
|
|
||||||
| using supported_celltypes = | ||||||
| Core::FE::CelltypeSequence<Core::FE::CellType::line2, Core::FE::CellType::line3>; | ||||||
| Core::FE::cell_type_switch<supported_celltypes>(element.shape(), | ||||||
| [&](auto celltype_t) | ||||||
| { | ||||||
| evaluate_normal_pressure<celltype_t()>(element, discretization, condition, dof_index_array, | ||||||
| force, load_linearization, total_time, reference_thickness, displacement_state); | ||||||
| }); | ||||||
| } | ||||||
|
|
||||||
| template <int dim> | ||||||
| void Discret::Elements::evaluate_neumann_by_element(Core::Elements::Element& element, | ||||||
| const Core::FE::Discretization& discretization, const Core::Conditions::Condition& condition, | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,8 +10,12 @@ | |
| #include "4C_config.hpp" | ||
|
|
||
| #include "4C_fem_general_element.hpp" | ||
| #include "4C_fem_general_element_integration.hpp" | ||
| #include "4C_linalg_fixedsizematrix.hpp" | ||
| #include "4C_linalg_serialdensematrix.hpp" | ||
| #include "4C_linalg_serialdensevector.hpp" | ||
|
|
||
| #include <array> | ||
| #include <vector> | ||
|
|
||
| FOUR_C_NAMESPACE_OPEN | ||
|
|
@@ -23,6 +27,60 @@ namespace Core::FE | |
|
|
||
| namespace Discret::Elements | ||
| { | ||
| template <Core::FE::CellType celltype> | ||
| requires(Core::FE::dim<celltype> == 1) | ||
| /*! | ||
| * @brief Add pressure normal to a plane solid boundary. | ||
| * | ||
| * The pressure is multiplied by the parent solid's reference thickness. If requested, this | ||
| * function also assembles the consistent negative load linearization used by the structural | ||
| * residual. | ||
| */ | ||
| void add_normal_pressure_load(const Core::Elements::ShapeFunctionsAndDerivatives<celltype>& shape, | ||
| const Core::LinAlg::Matrix<Core::FE::num_nodes(celltype), 2>& current_coordinates, | ||
| const double pressure_times_weight, const double reference_thickness, | ||
| const int num_dof_per_node, Core::LinAlg::SerialDenseVector& force, | ||
| Core::LinAlg::SerialDenseMatrix* load_linearization) | ||
| { | ||
| double radial_derivative = 0.0; | ||
| double axial_derivative = 0.0; | ||
| for (int node = 0; node < Core::FE::num_nodes(celltype); ++node) | ||
| { | ||
| radial_derivative += shape.derivatives(0, node) * current_coordinates(node, 0); | ||
| axial_derivative += shape.derivatives(0, node) * current_coordinates(node, 1); | ||
| } | ||
|
|
||
| const std::array<double, 2> normal_measure{ | ||
| reference_thickness * axial_derivative, -reference_thickness * radial_derivative}; | ||
| for (int node = 0; node < Core::FE::num_nodes(celltype); ++node) | ||
|
Comment on lines
+39
to
+55
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The function implementation could be moved to the .cpp. Also, I think that it would benefit a lot from formulae added as comments for each step of the computation (along with doxygen for the parameters and so on ;) ). Also: does it need to be exposed in the hpp, or could it be simply implemented as a helper function in an anonymous namespace in the corresponding cpp? As far as I see, it's only used within UPDATE: After looking over the unit test it's fine for me to keep it here, as it makes testing the functionality a bit more accessible as described in the respective comment. |
||
| for (int component = 0; component < 2; ++component) | ||
| force[node * num_dof_per_node + component] += | ||
| shape.values(node) * pressure_times_weight * normal_measure[component]; | ||
|
|
||
| if (load_linearization == nullptr) return; | ||
|
|
||
| for (int force_node = 0; force_node < Core::FE::num_nodes(celltype); ++force_node) | ||
| for (int coordinate_node = 0; coordinate_node < Core::FE::num_nodes(celltype); | ||
| ++coordinate_node) | ||
| { | ||
| const double factor = shape.values(force_node) * pressure_times_weight * | ||
| reference_thickness * shape.derivatives(0, coordinate_node); | ||
| (*load_linearization)( | ||
| force_node* num_dof_per_node, coordinate_node* num_dof_per_node + 1) -= factor; | ||
| (*load_linearization)( | ||
| force_node* num_dof_per_node + 1, coordinate_node * num_dof_per_node) += factor; | ||
|
Comment on lines
+66
to
+71
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe I'm missing something, but doesn't the current computation assume that the applied pressure is spatially homogeneous? Otherwise we would have a contribution from |
||
| } | ||
| } | ||
|
|
||
| /*! | ||
| * @brief Evaluate pseudo-orthopressure or follower orthopressure on a plane solid boundary line. | ||
| */ | ||
| void evaluate_normal_pressure_by_element(Core::Elements::Element& element, | ||
| const Core::FE::Discretization& discretization, const Core::Conditions::Condition& condition, | ||
| const std::vector<int>& dof_index_array, Core::LinAlg::SerialDenseVector& force, | ||
| Core::LinAlg::SerialDenseMatrix* load_linearization, double total_time, | ||
| double reference_thickness); | ||
|
|
||
| /*! | ||
| * @brief Evaluates a Neumann condition @p condition for the element @p element. | ||
| * | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not really acquainted with the orthopressure conditions, but this is the current convention right? This would mean that the function id and values should also be posed on the first dof, would it make sense to add these consistency conditions here as well?