diff --git a/README.md b/README.md index 0d3a398..01bf6b9 100644 --- a/README.md +++ b/README.md @@ -91,5 +91,8 @@ UK Atomic Energy Authority Alexander Whittle, UK Atomic Energy Authority +Bill Ellis, +UK Atomic Energy Authority + Pranav Naduvakkate, UK Atomic Energy Authority diff --git a/include/constraints/RBEConstraint.h b/include/constraints/RBEConstraint.h new file mode 100644 index 0000000..7f24e21 --- /dev/null +++ b/include/constraints/RBEConstraint.h @@ -0,0 +1,17 @@ +#pragma once +#include "NodalConstraint.h" + +class RBEConstraint : public NodalConstraint +{ + public: + static InputParameters validParams(); + RBEConstraint(const InputParameters & parameters); + + protected: + virtual Real computeQpResidual(Moose::ConstraintType type) override; + virtual Real computeQpJacobian(Moose::ConstraintJacobianType type) override; + std::string _primary_node_set_id; + std::string _secondary_node_set_id; + Real _penalty; + Real _primary_size; +}; diff --git a/src/constraints/RBEConstraint.C b/src/constraints/RBEConstraint.C new file mode 100644 index 0000000..f425e6b --- /dev/null +++ b/src/constraints/RBEConstraint.C @@ -0,0 +1,108 @@ +#include "RBEConstraint.h" +#include "MooseMesh.h" + +registerMooseObject("ProteusApp", RBEConstraint); + +InputParameters +RBEConstraint::validParams() +{ + InputParameters params = NodalConstraint::validParams(); + params.addClassDescription( + "Constrains secondary node to move as a linear combination of primary nodes. " + "Implementation of a Rigid Body Element Constraint"); + params.addRequiredParam("primary_node_set", + "The boundary ID associated with the primary nodes."); + params.addRequiredParam("secondary_node_set", + "The boundary ID associated with the secondary node."); + params.addRequiredParam("penalty", "The penalty used for the boundary term."); + params.addRequiredParam("primary_size", "The number of nodes in the primary node set."); + return params; +} + +RBEConstraint::RBEConstraint(const InputParameters & parameters) + : NodalConstraint(parameters), + _primary_node_set_id(getParam("primary_node_set")), + _secondary_node_set_id(getParam("secondary_node_set")), + _penalty(getParam("penalty")), + _primary_size(getParam("primary_size")) +{ + const auto & lm_mesh = _mesh.getMesh(); + + // Get secondary nodes + std::vector nodelist = + _mesh.getNodeList(_mesh.getBoundaryID(_secondary_node_set_id)); + std::vector::iterator in; + + for (in = nodelist.begin(); in != nodelist.end(); ++in) + { + const Node * const node = lm_mesh.query_node_ptr(*in); + if (node && node->processor_id() == _subproblem.processor_id()) + _connected_nodes.push_back(*in); + } + + // Get primary nodes + std::vector primary_nodelist = + _mesh.getNodeList(_mesh.getBoundaryID(_primary_node_set_id)); + + const auto & node_to_elem_map = _mesh.nodeToElemMap(); + + for (in = primary_nodelist.begin(); in != primary_nodelist.end(); ++in) + { + auto node_to_elem_pair = node_to_elem_map.find(*in); + if (node_to_elem_pair == node_to_elem_map.end()) + continue; + + _primary_node_vector.push_back(*in); + const std::vector & elems = node_to_elem_pair->second; + for (const auto & elem_id : elems) + { + _subproblem.addGhostedElem(elem_id); + } + } + _weights = std::vector(_primary_size, 1.0/_primary_size); +} + +Real +RBEConstraint::computeQpResidual(Moose::ConstraintType type) +{ +/* +Secondary residual is u_secondary - weights[1]*u_primary[1] + - weights[2]*u_primary[2] - u_primary[n]*weights[n] +However, computeQpResidual is calculated for only a combination of one +primary and one secondary node at a time. To get around this, the residual is +split up such that the final secondary residual resembles the above expression. +*/ + unsigned int primary_size = _primary_size; + + switch (type) + { + case Moose::Primary: + return (_u_primary[_j] * _weights[_j] - _u_secondary[_i] / primary_size) + * _penalty; + case Moose::Secondary: + return (_u_secondary[_i] / primary_size - _u_primary[_j] * _weights[_j]) + * _penalty; + } + return 0; +} + +Real +RBEConstraint::computeQpJacobian(Moose::ConstraintJacobianType type) +{ + unsigned int primary_size = _primary_size; + + switch (type) + { + case Moose::PrimaryPrimary: + return _penalty * _weights[_j]; + case Moose::PrimarySecondary: + return -_penalty / primary_size; + case Moose::SecondarySecondary: + return _penalty / primary_size; + case Moose::SecondaryPrimary: + return -_penalty * _weights[_j]; + default: + mooseError("Unsupported type"); + } + return 0; +}