Line data Source code
1 : //* This file is part of the MOOSE framework 2 : //* https://mooseframework.inl.gov 3 : //* 4 : //* All rights reserved, see COPYRIGHT for full restrictions 5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT 6 : //* 7 : //* Licensed under LGPL 2.1, please see LICENSE for details 8 : //* https://www.gnu.org/licenses/lgpl-2.1.html 9 : 10 : // MOOSE includes 11 : #include "LinearNodalConstraint.h" 12 : #include "MooseMesh.h" 13 : 14 : registerMooseObject("MooseApp", LinearNodalConstraint); 15 : 16 : InputParameters 17 14301 : LinearNodalConstraint::validParams() 18 : { 19 14301 : InputParameters params = NodalConstraint::validParams(); 20 14301 : params.addClassDescription( 21 : "Constrains secondary node to move as a linear combination of primary nodes."); 22 14301 : params.addRequiredParam<std::vector<unsigned int>>("primary", "The primary node IDs."); 23 14301 : params.addParam<std::vector<unsigned int>>( 24 : "secondary_node_ids", {}, "The list of secondary node ids"); 25 14301 : params.addParam<BoundaryName>( 26 : "secondary_node_set", "NaN", "The boundary ID associated with the secondary side"); 27 14301 : params.addRequiredParam<Real>("penalty", "The penalty used for the boundary term"); 28 14301 : params.addRequiredParam<std::vector<Real>>("weights", 29 : "The weights associated with the primary node ids. " 30 : "Must be of the same size as primary nodes"); 31 14301 : return params; 32 0 : } 33 : 34 18 : LinearNodalConstraint::LinearNodalConstraint(const InputParameters & parameters) 35 : : NodalConstraint(parameters), 36 18 : _primary_node_ids(getParam<std::vector<unsigned int>>("primary")), 37 18 : _secondary_node_ids(getParam<std::vector<unsigned int>>("secondary_node_ids")), 38 18 : _secondary_node_set_id(getParam<BoundaryName>("secondary_node_set")), 39 36 : _penalty(getParam<Real>("penalty")) 40 : { 41 18 : _weights = getParam<std::vector<Real>>("weights"); 42 : 43 18 : if (_primary_node_ids.size() != _weights.size()) 44 0 : mooseError("primary and weights should be of equal size."); 45 : 46 18 : const auto & lm_mesh = _mesh.getMesh(); 47 : 48 18 : if ((_secondary_node_ids.size() == 0) && (_secondary_node_set_id == "NaN")) 49 0 : mooseError("Please specify secondary_node_ids or secondary_node_set."); 50 18 : else if ((_secondary_node_ids.size() == 0) && (_secondary_node_set_id != "NaN")) 51 : { 52 : std::vector<dof_id_type> nodelist = 53 0 : _mesh.getNodeList(_mesh.getBoundaryID(_secondary_node_set_id)); 54 0 : std::vector<dof_id_type>::iterator in; 55 : 56 0 : for (in = nodelist.begin(); in != nodelist.end(); ++in) 57 : { 58 0 : const Node * const node = lm_mesh.query_node_ptr(*in); 59 0 : if (node && node->processor_id() == _subproblem.processor_id()) 60 0 : _connected_nodes.push_back(*in); // defining secondary nodes in the base class 61 : } 62 0 : } 63 18 : else if ((_secondary_node_ids.size() > 0) && (_secondary_node_set_id == "NaN")) 64 : { 65 36 : for (const auto & dof : _secondary_node_ids) 66 : { 67 18 : const Node * const node = lm_mesh.query_node_ptr(dof); 68 18 : if (node && node->processor_id() == _subproblem.processor_id()) 69 18 : _connected_nodes.push_back(dof); 70 : } 71 : } 72 : 73 18 : const auto & node_to_elem_map = _mesh.nodeToElemMap(); 74 : 75 : // Add elements connected to primary node to Ghosted Elements 76 36 : for (const auto & dof : _primary_node_ids) 77 : { 78 18 : auto node_to_elem_pair = node_to_elem_map.find(dof); 79 : 80 : // Our mesh may be distributed 81 18 : if (node_to_elem_pair == node_to_elem_map.end()) 82 0 : continue; 83 : 84 : // defining primary nodes in base class 85 18 : _primary_node_vector.push_back(dof); 86 : 87 18 : const std::vector<dof_id_type> & elems = node_to_elem_pair->second; 88 : 89 36 : for (const auto & elem_id : elems) 90 18 : _subproblem.addGhostedElem(elem_id); 91 : } 92 18 : } 93 : 94 : Real 95 224 : LinearNodalConstraint::computeQpResidual(Moose::ConstraintType type) 96 : { 97 : /** 98 : * Secondary residual is u_secondary - weights[1]*u_primary[1]-weights[2]*u_primary[2] ... 99 : *-u_primary[n]*weights[n] 100 : * However, computeQPresidual is calculated for only a combination of one primary and one 101 : *secondary node at a time. To get around this, the residual is split up such that the final 102 : *secondary residual resembles the above expression. 103 : **/ 104 : 105 224 : unsigned int primary_size = _primary_node_ids.size(); 106 : 107 224 : switch (type) 108 : { 109 112 : case Moose::Primary: 110 112 : return (_u_primary[_j] * _weights[_j] - _u_secondary[_i] / primary_size) * _penalty; 111 112 : case Moose::Secondary: 112 112 : return (_u_secondary[_i] / primary_size - _u_primary[_j] * _weights[_j]) * _penalty; 113 : } 114 0 : return 0.; 115 : } 116 : 117 : Real 118 96 : LinearNodalConstraint::computeQpJacobian(Moose::ConstraintJacobianType type) 119 : { 120 96 : unsigned int primary_size = _primary_node_ids.size(); 121 : 122 96 : switch (type) 123 : { 124 24 : case Moose::PrimaryPrimary: 125 24 : return _penalty * _weights[_j]; 126 24 : case Moose::PrimarySecondary: 127 24 : return -_penalty / primary_size; 128 24 : case Moose::SecondarySecondary: 129 24 : return _penalty / primary_size; 130 24 : case Moose::SecondaryPrimary: 131 24 : return -_penalty * _weights[_j]; 132 0 : default: 133 0 : mooseError("Unsupported type"); 134 : break; 135 : } 136 : return 0.; 137 : }