Skip to content
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

Adapt Robin / Neumann boundary conditions to user needs. #2710

Merged
merged 7 commits into from Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -0,0 +1,8 @@
Typically boundary conditions are set on domains with dimension exactly one
lower than the bulk mesh dimension. In some cases the boundary condition should
be set on entities that have lower dimension than one lower. For instance
boundary conditions on points in 2d or 3d domains or boundary conditions on
lines in 3d domains.

In order not to integrate over a null set the area tag can be used to specify
the area the boundary condition should be effective.
@@ -0,0 +1,8 @@
Typically boundary conditions are set on domains with dimension exactly one
lower than the bulk mesh dimension. In some cases the boundary condition should
be set on entities that have lower dimension than one lower. For instance
boundary conditions on points in 2d or 3d domains or boundary conditions on
lines in 3d domains.

In order not to integrate over a null set the area tag can be used to specify
the area the boundary condition should be effective.
Expand Up @@ -43,14 +43,6 @@ GenericNaturalBoundaryCondition<BoundaryConditionData,
dof_table_bulk.getNumberOfVariableComponents(variable_id));
}

if (_bc_mesh.getDimension() + 1 != global_dim)
{
OGS_FATAL(
"The dimension (%d) of the given boundary mesh '%s' is not by one "
"lower than the bulk dimension (%d).",
_bc_mesh.getDimension(), _bc_mesh.getName().c_str(), global_dim);
}

if (!_bc_mesh.getProperties().template existsPropertyVector<std::size_t>(
"bulk_node_ids"))
{
Expand Down
Expand Up @@ -30,6 +30,14 @@ createHCNonAdvectiveFreeComponentFlowBoundaryCondition(
config.checkConfigParameter("type",
"HCNonAdvectiveFreeComponentFlowBoundary");

if (bc_mesh.getDimension() + 1 != global_dim)
{
OGS_FATAL(
"The dimension (%d) of the given boundary mesh '%s' is not by one "
"lower than the bulk dimension (%d).",
bc_mesh.getDimension(), bc_mesh.getName().c_str(), global_dim);
}

auto const boundary_permeability_name =
//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__HCNonAdvectiveFreeComponentFlowBoundary__parameter}
config.getConfigParameter<std::string>("parameter");
Expand Down
26 changes: 23 additions & 3 deletions ProcessLib/BoundaryCondition/NeumannBoundaryCondition.cpp
Expand Up @@ -31,8 +31,8 @@ std::unique_ptr<NeumannBoundaryCondition> createNeumannBoundaryCondition(
auto const& param = ParameterLib::findParameter<double>(
param_name, parameters, 1, &bc_mesh);

// In case of partitioned mesh the boundary could be empty, i.e. there is no
// boundary condition.
// In case of partitioned mesh the boundary could be empty, i.e. there
// is no boundary condition.
#ifdef USE_PETSC
// This can be extracted to createBoundaryCondition() but then the config
// parameters are not read and will cause an error.
Expand All @@ -45,9 +45,29 @@ std::unique_ptr<NeumannBoundaryCondition> createNeumannBoundaryCondition(
}
#endif // USE_PETSC

ParameterLib::Parameter<double> const* integral_measure(nullptr);
if (global_dim - bc_mesh.getDimension() != 1)
{
//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__Neumann__area_parameter}
auto const area_parameter_name =
config.getConfigParameter<std::string>("area_parameter");
DBUG("area parameter name '%s'", area_parameter_name.c_str());
integral_measure = &ParameterLib::findParameter<double>(
area_parameter_name, parameters, 1, &bc_mesh);
}

if (bc_mesh.getDimension() >= global_dim)
{
OGS_FATAL(
"The dimension (%d) of the given boundary mesh '%s' is not lower "
"than the bulk dimension (%d).",
bc_mesh.getDimension(), bc_mesh.getName().c_str(), global_dim);
}

return std::make_unique<NeumannBoundaryCondition>(
integration_order, shapefunction_order, dof_table, variable_id,
component_id, global_dim, bc_mesh, param);
component_id, global_dim, bc_mesh,
NeumannBoundaryConditionData{param, integral_measure});
}

} // namespace ProcessLib
2 changes: 1 addition & 1 deletion ProcessLib/BoundaryCondition/NeumannBoundaryCondition.h
Expand Up @@ -17,7 +17,7 @@
namespace ProcessLib
{
using NeumannBoundaryCondition =
GenericNaturalBoundaryCondition<ParameterLib::Parameter<double> const&,
GenericNaturalBoundaryCondition<NeumannBoundaryConditionData,
NeumannBoundaryConditionLocalAssembler>;

std::unique_ptr<NeumannBoundaryCondition> createNeumannBoundaryCondition(
Expand Down
Expand Up @@ -18,6 +18,12 @@

namespace ProcessLib
{
struct NeumannBoundaryConditionData final
{
ParameterLib::Parameter<double> const& neumann_bc_parameter;
ParameterLib::Parameter<double> const* const integral_measure;
};

template <typename ShapeFunction, typename IntegrationMethod,
unsigned GlobalDim>
class NeumannBoundaryConditionLocalAssembler final
Expand All @@ -37,9 +43,9 @@ class NeumannBoundaryConditionLocalAssembler final
std::size_t const local_matrix_size,
bool const is_axially_symmetric,
unsigned const integration_order,
ParameterLib::Parameter<double> const& neumann_bc_parameter)
NeumannBoundaryConditionData const& data)
: Base(e, is_axially_symmetric, integration_order),
_neumann_bc_parameter(neumann_bc_parameter),
_data(data),
_local_rhs(local_matrix_size)
{
}
Expand All @@ -58,24 +64,36 @@ class NeumannBoundaryConditionLocalAssembler final
// Get element nodes for the interpolation from nodes to integration
// point.
NodalVectorType parameter_node_values =
_neumann_bc_parameter.getNodalValuesOnElement(Base::_element, t)
_data.neumann_bc_parameter
.getNodalValuesOnElement(Base::_element, t)
.template topRows<ShapeFunction::MeshElement::n_all_nodes>();

ParameterLib::SpatialPosition position;
position.setElementID(Base::_element.getID());

double integral_measure = 1.0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove it if the following suggestion (fro lines 82-84) is taken .

for (unsigned ip = 0; ip < n_integration_points; ip++)
{
position.setIntegrationPoint(ip);
auto const& ip_data = Base::_ns_and_weights[ip];
auto const& N = ip_data.N;
auto const& w = ip_data.weight;

_local_rhs.noalias() += ip_data.N *
parameter_node_values.dot(ip_data.N) *
ip_data.weight;
if (_data.integral_measure)
{
integral_measure = (*_data.integral_measure)(t, position)[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
integral_measure = (*_data.integral_measure)(t, position)[0];
const double integral_measure = (_data.integral_measure) ? (*_data.integral_measure)(t, position)[0] : 1.0;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this doesn't work. See the argument in the RobinBoundaryConditionLocalAssembler case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.

}
_local_rhs.noalias() +=
N * parameter_node_values.dot(N) * w * integral_measure;
}

auto const indices = NumLib::getIndices(id, dof_table_boundary);
b.add(indices, _local_rhs);
}

private:
ParameterLib::Parameter<double> const& _neumann_bc_parameter;
NeumannBoundaryConditionData const& _data;

NodalVectorType _local_rhs;

public:
Expand Down
22 changes: 20 additions & 2 deletions ProcessLib/BoundaryCondition/RobinBoundaryCondition.cpp
Expand Up @@ -25,17 +25,35 @@ std::unique_ptr<RobinBoundaryCondition> createRobinBoundaryCondition(
//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__type}
config.checkConfigParameter("type", "Robin");

if (bc_mesh.getDimension() >= global_dim)
{
OGS_FATAL(
"The dimension (%d) of the given boundary mesh '%s' is not lower "
"than the bulk dimension (%d).",
bc_mesh.getDimension(), bc_mesh.getName().c_str(), global_dim);
}

//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__Robin__alpha}
auto const alpha_name = config.getConfigParameter<std::string>("alpha");
//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__Robin__u_0}
auto const u_0_name = config.getConfigParameter<std::string>("u_0");

auto const& alpha = ParameterLib::findParameter<double>(
alpha_name, parameters, 1, &bc_mesh);

auto const& u_0 =
ParameterLib::findParameter<double>(u_0_name, parameters, 1, &bc_mesh);

ParameterLib::Parameter<double> const* integral_measure(nullptr);
if (global_dim - bc_mesh.getDimension() != 1)
{
//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__Robin__area_parameter}
auto const area_parameter_name =
config.getConfigParameter<std::string>("area_parameter");
DBUG("area parameter name '%s'", area_parameter_name.c_str());
integral_measure = &ParameterLib::findParameter<double>(
area_parameter_name, parameters, 1, &bc_mesh);
}

// In case of partitioned mesh the boundary could be empty, i.e. there is no
// boundary condition.
#ifdef USE_PETSC
Expand All @@ -53,7 +71,7 @@ std::unique_ptr<RobinBoundaryCondition> createRobinBoundaryCondition(
return std::make_unique<RobinBoundaryCondition>(
integration_order, shapefunction_order, dof_table, variable_id,
component_id, global_dim, bc_mesh,
RobinBoundaryConditionData{alpha, u_0});
RobinBoundaryConditionData{alpha, u_0, integral_measure});
}

} // namespace ProcessLib
Expand Up @@ -20,6 +20,7 @@ struct RobinBoundaryConditionData final
{
ParameterLib::Parameter<double> const& alpha;
ParameterLib::Parameter<double> const& u_0;
ParameterLib::Parameter<double> const* const integral_measure;
};

template <typename ShapeFunction, typename IntegrationMethod,
Expand Down Expand Up @@ -64,17 +65,29 @@ class RobinBoundaryConditionLocalAssembler final
_data.u_0.getNodalValuesOnElement(Base::_element, t)
.template topRows<ShapeFunction::MeshElement::n_all_nodes>();

ParameterLib::SpatialPosition position;
position.setElementID(Base::_element.getID());

for (unsigned ip = 0; ip < n_integration_points; ++ip)
{
position.setIntegrationPoint(ip);
auto const& ip_data = Base::_ns_and_weights[ip];
auto const& N = ip_data.N;
auto const& w = ip_data.weight;

double integral_measure = 1.0;
if (_data.integral_measure)
{
integral_measure = (*_data.integral_measure)(t, position)[0];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
integral_measure = (*_data.integral_measure)(t, position)[0];
const double integral_measure = (_data.integral_measure) ? (*_data.integral_measure)(t, position)[0] : 1.0;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't declare/define the variable integral_measure only in the scope of the branch of the if condition since it is used below.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}

// flux = alpha * ( u_0 - u )
// adding a alpha term to the diagonal of the stiffness matrix
// and a alpha * u_0 term to the rhs vector
_local_K.diagonal().noalias() += N * alpha.dot(N) * w;
_local_rhs.noalias() += N * alpha.dot(N) * u_0.dot(N) * w;
_local_K.diagonal().noalias() +=
N * alpha.dot(N) * w * integral_measure;
_local_rhs.noalias() +=
N * alpha.dot(N) * u_0.dot(N) * w * integral_measure;
}

auto const indices = NumLib::getIndices(id, dof_table_boundary);
Expand Down
Expand Up @@ -33,6 +33,14 @@ createVariableDependentNeumannBoundaryCondition(
}
assert(variable_id == 0 || variable_id == 1);

if (bc_mesh.getDimension() + 1 != global_dim)
{
OGS_FATAL(
"The dimension (%d) of the given boundary mesh '%s' is not by one "
"lower than the bulk dimension (%d).",
bc_mesh.getDimension(), bc_mesh.getName().c_str(), global_dim);
}

auto const constant_name =
//! \ogs_file_param{prj__process_variables__process_variable__boundary_conditions__boundary_condition__VariableDependentNeumann__constant_name}
config.getConfigParameter<std::string>("constant_name");
Expand Down
8 changes: 4 additions & 4 deletions ProcessLib/ComponentTransport/Tests.cmake
Expand Up @@ -651,13 +651,13 @@ AddTest(
REQUIREMENTS OGS_USE_MPI
DIFF_DATA
TracerSimulation_pcs_1_ts_100_t_100000_000000_0_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_0.vtu Cs Cs 1e-10 1e-16
TracerSimulation_pcs_1_ts_100_t_100000_000000_0_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_0.vtu pressure pressure 1e-6 1e-10
TracerSimulation_pcs_1_ts_100_t_100000_000000_0_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_0.vtu pressure pressure 2.5e-5 1.7e-9
TracerSimulation_pcs_1_ts_100_t_100000_000000_1_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_1.vtu Cs Cs 1e-10 1e-16
TracerSimulation_pcs_1_ts_100_t_100000_000000_1_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_1.vtu pressure pressure 1e-6 1e-10
TracerSimulation_pcs_1_ts_100_t_100000_000000_1_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_1.vtu pressure pressure 2.5e-5 1.7e-9
TracerSimulation_pcs_1_ts_100_t_100000_000000_2_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_2.vtu Cs Cs 1e-10 1e-16
TracerSimulation_pcs_1_ts_100_t_100000_000000_2_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_2.vtu pressure pressure 1e-6 1e-10
TracerSimulation_pcs_1_ts_100_t_100000_000000_2_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_2.vtu pressure pressure 2.5e-5 1.7e-9
TracerSimulation_pcs_1_ts_100_t_100000_000000_3_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_3.vtu Cs Cs 1e-10 1e-16
TracerSimulation_pcs_1_ts_100_t_100000_000000_3_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_3.vtu pressure pressure 1e-6 1e-10
TracerSimulation_pcs_1_ts_100_t_100000_000000_3_expected.vtu TracerSimulation_pcs_1_ts_100_t_100000_000000_3.vtu pressure pressure 2.5e-5 1.7e-9
)

AddTest(
Expand Down
24 changes: 24 additions & 0 deletions ProcessLib/GroundwaterFlow/Tests.cmake
Expand Up @@ -708,6 +708,30 @@ AddTest(
square_1x1_quad_1e3_volumetricsourceterm_analytical_solution.vtu square_1e3_volumetricsourceterm_pcs_0_ts_1_t_1.000000.vtu analytical_solution pressure 1e-10 1e-11
)

AddTest(
NAME GroundWaterFlowProcess_NeumannBC_Along_Line_in_3D_domain
PATH Elliptic/quarter_disc
EXECUTABLE ogs
EXECUTABLE_ARGS quarter_disc_neumann.prj
WRAPPER time
TESTER vtkdiff
REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI)
DIFF_DATA
quarter_disc_r_1.vtu neumann_along_line_pcs_0_ts_1_t_1.000000.vtu analytical_solution pressure 6e-5 0
)

AddTest(
NAME GroundWaterFlowProcess_NeumannBC_In_Center_Point_2D_domain
PATH Elliptic/quarter_circle
EXECUTABLE ogs
EXECUTABLE_ARGS quarter_circle_neumann.prj
WRAPPER time
TESTER vtkdiff
REQUIREMENTS NOT (OGS_USE_LIS OR OGS_USE_MPI)
DIFF_DATA
quarter_circle_r_1.vtu neumann_in_center_pcs_0_ts_1_t_1.000000.vtu pressure_nodal_source_term pressure 1e-14 1e-14
)

AddTest(
NAME GroundWaterFlowProcess_VolumetricSourceTerm_sin_x_sin_y_square_1e3
PATH Elliptic/square_1x1_GroundWaterFlow
Expand Down