diff --git a/ProcessLib/BoundaryCondition/BoundaryCondition.cpp b/ProcessLib/BoundaryCondition/BoundaryCondition.cpp index 8df5b5e7bf7354726d678fb06b8969f5e76ebe87..3b0875555d438a3131721567f659fab023dcd51f 100644 --- a/ProcessLib/BoundaryCondition/BoundaryCondition.cpp +++ b/ProcessLib/BoundaryCondition/BoundaryCondition.cpp @@ -8,13 +8,14 @@ */ #include "BoundaryCondition.h" +#include "BoundaryConditionConfig.h" +#include "DirichletBoundaryCondition.h" #include "MeshGeoToolsLib/BoundaryElementsSearcher.h" +#include "MeshGeoToolsLib/CreateSearchLength.h" #include "MeshGeoToolsLib/MeshNodeSearcher.h" #include "MeshGeoToolsLib/SearchLength.h" -#include "MeshGeoToolsLib/CreateSearchLength.h" -#include "BoundaryConditionConfig.h" -#include "DirichletBoundaryCondition.h" #include "NeumannBoundaryCondition.h" +#include "NonuniformNeumannBoundaryCondition.h" #include "RobinBoundaryCondition.h" namespace ProcessLib @@ -48,6 +49,12 @@ BoundaryConditionBuilder::createBoundaryCondition( config, dof_table, mesh, variable_id, integration_order, shapefunction_order, parameters); } + if (type == "NonuniformNeumann") + { + return createNonuniformNeumannBoundaryCondition( + config, dof_table, mesh, variable_id, integration_order, + shapefunction_order, parameters); + } OGS_FATAL("Unknown boundary condition type: `%s'.", type.c_str()); } @@ -158,6 +165,32 @@ BoundaryConditionBuilder::createRobinBoundaryCondition( parameters); } +std::unique_ptr<BoundaryCondition> +BoundaryConditionBuilder::createNonuniformNeumannBoundaryCondition( + const BoundaryConditionConfig& config, + const NumLib::LocalToGlobalIndexMap& dof_table, const MeshLib::Mesh& mesh, + const int variable_id, const unsigned integration_order, + const unsigned shapefunction_order, + const std::vector<std::unique_ptr<ProcessLib::ParameterBase>>& parameters) +{ + std::unique_ptr<MeshGeoToolsLib::SearchLength> search_length_algorithm = + MeshGeoToolsLib::createSearchLengthAlgorithm(config.config, mesh); + + MeshGeoToolsLib::MeshNodeSearcher const& mesh_node_searcher = + MeshGeoToolsLib::MeshNodeSearcher::getMeshNodeSearcher( + mesh, std::move(search_length_algorithm)); + + MeshGeoToolsLib::BoundaryElementsSearcher boundary_element_searcher( + mesh, mesh_node_searcher); + + return ProcessLib::createNonuniformNeumannBoundaryCondition( + config.config, + getClonedElements(boundary_element_searcher, config.geometry), + dof_table, variable_id, config.component_id, mesh.isAxiallySymmetric(), + integration_order, shapefunction_order, mesh.getDimension(), + parameters); +} + std::vector<MeshLib::Element*> BoundaryConditionBuilder::getClonedElements( MeshGeoToolsLib::BoundaryElementsSearcher& boundary_element_searcher, GeoLib::GeoObject const& geometry) diff --git a/ProcessLib/BoundaryCondition/BoundaryCondition.h b/ProcessLib/BoundaryCondition/BoundaryCondition.h index e72923933438ca38cd5bdb42769f3e3051c260cc..fce30ffe566cda1aba4ca838ce90491d137d9da9 100644 --- a/ProcessLib/BoundaryCondition/BoundaryCondition.h +++ b/ProcessLib/BoundaryCondition/BoundaryCondition.h @@ -107,6 +107,15 @@ protected: const std::vector<std::unique_ptr<ProcessLib::ParameterBase>>& parameters); + virtual std::unique_ptr<BoundaryCondition> + createNonuniformNeumannBoundaryCondition( + const BoundaryConditionConfig& config, + const NumLib::LocalToGlobalIndexMap& dof_table, + const MeshLib::Mesh& mesh, const int variable_id, + const unsigned integration_order, const unsigned shapefunction_order, + const std::vector<std::unique_ptr<ProcessLib::ParameterBase>>& + parameters); + static std::vector<MeshLib::Element*> getClonedElements( MeshGeoToolsLib::BoundaryElementsSearcher& boundary_element_searcher, GeoLib::GeoObject const& geometry); diff --git a/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryCondition-impl.h b/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryCondition-impl.h new file mode 100644 index 0000000000000000000000000000000000000000..3a08a06be3b0ec07d4fa61bd7a8d0f07b8acdaec --- /dev/null +++ b/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryCondition-impl.h @@ -0,0 +1,90 @@ +/** + * \copyright + * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "GenericNonuniformNaturalBoundaryCondition.h" +#include "GenericNonuniformNaturalBoundaryConditionLocalAssembler.h" +#include "MeshLib/MeshSearch/NodeSearch.h" +#include "ProcessLib/Utils/CreateLocalAssemblers.h" + +namespace ProcessLib +{ +template <typename BoundaryConditionData, + template <typename, typename, unsigned> + class LocalAssemblerImplementation> +template <typename Data> +GenericNonuniformNaturalBoundaryCondition<BoundaryConditionData, + LocalAssemblerImplementation>:: + GenericNonuniformNaturalBoundaryCondition( + typename std::enable_if< + std::is_same<typename std::decay<BoundaryConditionData>::type, + typename std::decay<Data>::type>::value, + bool>::type is_axially_symmetric, + unsigned const integration_order, unsigned const shapefunction_order, + NumLib::LocalToGlobalIndexMap const& dof_table_bulk, + int const variable_id, int const component_id, + unsigned const global_dim, std::vector<MeshLib::Element*>&& elements, + Data&& data) + : _data(std::forward<Data>(data)), + _elements(std::move(elements)), + _integration_order(integration_order) +{ + assert(component_id < + static_cast<int>(dof_table_bulk.getNumberOfComponents())); + + std::vector<MeshLib::Node*> nodes = MeshLib::getUniqueNodes(_elements); + DBUG("Found %d nodes for Natural BCs for the variable %d and component %d", + nodes.size(), variable_id, component_id); + + auto const& mesh_subsets = + dof_table_bulk.getMeshSubsets(variable_id, component_id); + + // TODO extend the node intersection to all parts of mesh_subsets, i.e. + // to each of the MeshSubset in the mesh_subsets. + _mesh_subset_all_nodes.reset( + mesh_subsets.getMeshSubset(0).getIntersectionByNodes(nodes)); + MeshLib::MeshSubsets all_mesh_subsets{_mesh_subset_all_nodes.get()}; + + // Create local DOF table from intersected mesh subsets for the given + // variable and component ids. + _dof_table_boundary.reset(dof_table_bulk.deriveBoundaryConstrainedMap( + variable_id, {component_id}, std::move(all_mesh_subsets), _elements)); + + createLocalAssemblers<LocalAssemblerImplementation>( + global_dim, _elements, *_dof_table_boundary, shapefunction_order, + _local_assemblers, is_axially_symmetric, _integration_order, _data); +} + +template <typename BoundaryConditionData, + template <typename, typename, unsigned> + class LocalAssemblerImplementation> +GenericNonuniformNaturalBoundaryCondition< + BoundaryConditionData, + LocalAssemblerImplementation>::~GenericNonuniformNaturalBoundaryCondition() +{ + for (auto e : _elements) + delete e; +} + +template <typename BoundaryConditionData, + template <typename, typename, unsigned> + class LocalAssemblerImplementation> +void GenericNonuniformNaturalBoundaryCondition< + BoundaryConditionData, + LocalAssemblerImplementation>::applyNaturalBC(const double t, + const GlobalVector& x, + GlobalMatrix& K, + GlobalVector& b) +{ + GlobalExecutor::executeMemberOnDereferenced( + &GenericNonuniformNaturalBoundaryConditionLocalAssemblerInterface:: + assemble, + _local_assemblers, *_dof_table_boundary, t, x, K, b); +} + +} // ProcessLib diff --git a/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryCondition.h b/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryCondition.h new file mode 100644 index 0000000000000000000000000000000000000000..495b361adc9ba69e7a5610a97a4d9af8864fb239 --- /dev/null +++ b/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryCondition.h @@ -0,0 +1,74 @@ +/** + * \copyright + * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "BoundaryCondition.h" +#include "MeshLib/MeshSubset.h" + +namespace ProcessLib +{ +class GenericNonuniformNaturalBoundaryConditionLocalAssemblerInterface; + +template <typename BoundaryConditionData, + template <typename, typename, unsigned> + class LocalAssemblerImplementation> +class GenericNonuniformNaturalBoundaryCondition final : public BoundaryCondition +{ +public: + /// Create a boundary condition process from given config, + /// DOF-table, and a mesh subset for a given variable and its component. + /// A local DOF-table, a subset of the given one, is constructed. + template <typename Data> + GenericNonuniformNaturalBoundaryCondition( + typename std::enable_if< + std::is_same<typename std::decay<BoundaryConditionData>::type, + typename std::decay<Data>::type>::value, + bool>::type is_axially_symmetric, + unsigned const integration_order, unsigned const shapefunction_order, + NumLib::LocalToGlobalIndexMap const& dof_table_bulk, + int const variable_id, int const component_id, + unsigned const global_dim, std::vector<MeshLib::Element*>&& elements, + Data&& data); + + ~GenericNonuniformNaturalBoundaryCondition() override; + + /// Calls local assemblers which calculate their contributions to the global + /// matrix and the right-hand-side. + void applyNaturalBC(const double t, + GlobalVector const& x, + GlobalMatrix& K, + GlobalVector& b) override; + +private: + /// Data used in the assembly of the specific boundary condition. + BoundaryConditionData _data; + + /// Vector of lower-dimensional elements on which the boundary condition is + /// defined. + std::vector<MeshLib::Element*> _elements; + + std::unique_ptr<MeshLib::MeshSubset const> _mesh_subset_all_nodes; + + /// Local dof table, a subset of the global one restricted to the + /// participating #_elements of the boundary condition. + std::unique_ptr<NumLib::LocalToGlobalIndexMap> _dof_table_boundary; + + /// Integration order for integration over the lower-dimensional elements + unsigned const _integration_order; + + /// Local assemblers for each element of #_elements. + std::vector<std::unique_ptr< + GenericNonuniformNaturalBoundaryConditionLocalAssemblerInterface>> + _local_assemblers; +}; + +} // ProcessLib + +#include "GenericNonuniformNaturalBoundaryCondition-impl.h" diff --git a/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryConditionLocalAssembler.h b/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryConditionLocalAssembler.h new file mode 100644 index 0000000000000000000000000000000000000000..73eb6f9c14c8a49e5a1648bc0247d69ae8839499 --- /dev/null +++ b/ProcessLib/BoundaryCondition/GenericNonuniformNaturalBoundaryConditionLocalAssembler.h @@ -0,0 +1,58 @@ +/** + * \copyright + * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "NumLib/Fem/ShapeMatrixPolicy.h" +#include "ProcessLib/Utils/InitShapeMatrices.h" + +namespace ProcessLib +{ +class GenericNonuniformNaturalBoundaryConditionLocalAssemblerInterface +{ +public: + virtual ~GenericNonuniformNaturalBoundaryConditionLocalAssemblerInterface() = + default; + + virtual void assemble( + std::size_t const id, + NumLib::LocalToGlobalIndexMap const& dof_table_boundary, double const t, + const GlobalVector& x, GlobalMatrix& K, GlobalVector& b) = 0; +}; + +template <typename ShapeFunction, typename IntegrationMethod, + unsigned GlobalDim> +class GenericNonuniformNaturalBoundaryConditionLocalAssembler + : public GenericNonuniformNaturalBoundaryConditionLocalAssemblerInterface +{ +protected: + using ShapeMatricesType = ShapeMatrixPolicyType<ShapeFunction, GlobalDim>; + using NodalMatrixType = typename ShapeMatricesType::NodalMatrixType; + using NodalVectorType = typename ShapeMatricesType::NodalVectorType; + +public: + GenericNonuniformNaturalBoundaryConditionLocalAssembler( + MeshLib::Element const& e, bool is_axially_symmetric, + unsigned const integration_order) + : _integration_method(integration_order), + _shape_matrices(initShapeMatrices<ShapeFunction, ShapeMatricesType, + IntegrationMethod, GlobalDim>( + e, is_axially_symmetric, _integration_method)) + { + } + +protected: + IntegrationMethod const _integration_method; + std::vector<typename ShapeMatricesType::ShapeMatrices, + Eigen::aligned_allocator< + typename ShapeMatricesType::ShapeMatrices>> const + _shape_matrices; +}; + +} // ProcessLib diff --git a/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f50ca64070b9dca929910f7f1a82b2c18cbbebf --- /dev/null +++ b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.cpp @@ -0,0 +1,40 @@ +/** + * \copyright + * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#include "NonuniformNeumannBoundaryCondition.h" +#include "ProcessLib/Utils/ProcessUtils.h" + +namespace ProcessLib +{ +std::unique_ptr<NonuniformNeumannBoundaryCondition> +createNonuniformNeumannBoundaryCondition( + BaseLib::ConfigTree const& config, + std::vector<MeshLib::Element*>&& elements, + NumLib::LocalToGlobalIndexMap const& dof_table, int const variable_id, + int const component_id, bool is_axially_symmetric, + unsigned const integration_order, unsigned const shapefunction_order, + unsigned const global_dim, + std::vector<std::unique_ptr<ParameterBase>> const& parameters) +{ + DBUG("Constructing NonuniformNeumann BC from config."); + //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__type} + config.checkConfigParameter("type", "NonuniformNeumann"); + + //! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__NonuniformNeumann__parameter} + auto const param_name = config.getConfigParameter<std::string>("parameter"); + DBUG("Using parameter %s", param_name.c_str()); + + auto const& param = findParameter<double>(param_name, parameters, 1); + + return std::make_unique<NonuniformNeumannBoundaryCondition>( + is_axially_symmetric, integration_order, shapefunction_order, dof_table, + variable_id, component_id, global_dim, std::move(elements), param); +} + +} // ProcessLib diff --git a/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.h b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.h new file mode 100644 index 0000000000000000000000000000000000000000..c391a8dfc859270ce25d1e74e41e3ab8c7f20786 --- /dev/null +++ b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryCondition.h @@ -0,0 +1,33 @@ +/** + * \copyright + * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "GenericNonuniformNaturalBoundaryCondition.h" +#include "NonuniformNeumannBoundaryConditionLocalAssembler.h" +#include "ProcessLib/Parameter/Parameter.h" + +namespace ProcessLib +{ +using NonuniformNeumannBoundaryCondition = + GenericNonuniformNaturalBoundaryCondition< + Parameter<double> const&, + NonuniformNeumannBoundaryConditionLocalAssembler>; + +std::unique_ptr<NonuniformNeumannBoundaryCondition> +createNonuniformNeumannBoundaryCondition( + BaseLib::ConfigTree const& config, + std::vector<MeshLib::Element*>&& elements, + NumLib::LocalToGlobalIndexMap const& dof_table, int const variable_id, + int const component_id, bool is_axially_symmetric, + unsigned const integration_order, unsigned const shapefunction_order, + unsigned const global_dim, + std::vector<std::unique_ptr<ParameterBase>> const& parameters); + +} // ProcessLib diff --git a/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryConditionLocalAssembler.h b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryConditionLocalAssembler.h new file mode 100644 index 0000000000000000000000000000000000000000..4d736f8a60011ef746ba1af7985ca972b4baff87 --- /dev/null +++ b/ProcessLib/BoundaryCondition/NonuniformNeumannBoundaryConditionLocalAssembler.h @@ -0,0 +1,77 @@ +/** + * \copyright + * Copyright (c) 2012-2017, OpenGeoSys Community (http://www.opengeosys.org) + * Distributed under a Modified BSD License. + * See accompanying file LICENSE.txt or + * http://www.opengeosys.org/project/license + * + */ + +#pragma once + +#include "GenericNonuniformNaturalBoundaryConditionLocalAssembler.h" +#include "NumLib/DOF/DOFTableUtil.h" +#include "ProcessLib/Parameter/Parameter.h" + +namespace ProcessLib +{ +template <typename ShapeFunction, typename IntegrationMethod, + unsigned GlobalDim> +class NonuniformNeumannBoundaryConditionLocalAssembler final + : public GenericNonuniformNaturalBoundaryConditionLocalAssembler< + ShapeFunction, IntegrationMethod, GlobalDim> +{ + using Base = GenericNonuniformNaturalBoundaryConditionLocalAssembler< + ShapeFunction, IntegrationMethod, GlobalDim>; + +public: + /// The neumann_bc_value factor is directly integrated into the local + /// element matrix. + NonuniformNeumannBoundaryConditionLocalAssembler( + MeshLib::Element const& e, + std::size_t const local_matrix_size, + bool is_axially_symmetric, + unsigned const integration_order, + Parameter<double> const& neumann_bc_parameter) + : Base(e, is_axially_symmetric, integration_order), + _neumann_bc_parameter(neumann_bc_parameter), + _local_rhs(local_matrix_size) + { + } + + void assemble(std::size_t const id, + NumLib::LocalToGlobalIndexMap const& dof_table_boundary, + double const t, const GlobalVector& /*x*/, + GlobalMatrix& /*K*/, GlobalVector& b) override + { + _local_rhs.setZero(); + + unsigned const n_integration_points = + Base::_integration_method.getNumberOfPoints(); + + SpatialPosition pos; + pos.setElementID(id); + + for (unsigned ip = 0; ip < n_integration_points; ip++) + { + pos.setIntegrationPoint(ip); + auto const& sm = Base::_shape_matrices[ip]; + auto const& wp = Base::_integration_method.getWeightedPoint(ip); + _local_rhs.noalias() += sm.N * _neumann_bc_parameter(t, pos)[0] * + sm.detJ * wp.getWeight() * + sm.integralMeasure; + } + + auto const indices = NumLib::getIndices(id, dof_table_boundary); + b.add(indices, _local_rhs); + } + +private: + Parameter<double> const& _neumann_bc_parameter; + typename Base::NodalVectorType _local_rhs; + +public: + EIGEN_MAKE_ALIGNED_OPERATOR_NEW; +}; + +} // namespace ProcessLib