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 : #include "ProjectionAux.h" 11 : #include "SystemBase.h" 12 : #include "libmesh/system.h" 13 : 14 : registerMooseObjectRenamed("MooseApp", SelfAux, "01/30/2024 24:00", ProjectionAux); 15 : registerMooseObject("MooseApp", ProjectionAux); 16 : 17 : InputParameters 18 14121 : ProjectionAux::validParams() 19 : { 20 14121 : InputParameters params = AuxKernel::validParams(); 21 28242 : params.addClassDescription( 22 : "Returns the specified variable as an auxiliary variable with a projection of the source " 23 : "variable. If they are the same type, this amounts to a simple copy."); 24 56484 : params.addRequiredCoupledVar("v", "Variable to take the value of."); 25 : 26 42363 : params.addParam<bool>("use_block_restriction_for_source", 27 28242 : false, 28 : "Whether to use the auxkernel block restriction to also restrict the " 29 : "locations selected for source variable values"); 30 : 31 : // Technically possible to project from nodal to elemental and back 32 28242 : params.set<bool>("_allow_nodal_to_elemental_coupling") = true; 33 : 34 56484 : MooseEnum elem_to_node_projection_weighting("volume identity", "volume"); 35 42363 : params.addParam<MooseEnum>("elem_to_node_projection_weighting", 36 : elem_to_node_projection_weighting, 37 : "How to weight individual element contributions when projecting to a " 38 : "nodal degree of freedom"); 39 : 40 : // We need some ghosting for all elemental to nodal projections 41 42363 : params.addRelationshipManager( 42 : "GhostAllPointNeighbors", 43 : Moose::RelationshipManagerType::GEOMETRIC | Moose::RelationshipManagerType::ALGEBRAIC, 44 0 : [](const InputParameters & obj_params, InputParameters & rm_params) 45 34407 : { rm_params.set<bool>("use_displaced_mesh") = obj_params.get<bool>("use_displaced_mesh"); }); 46 28242 : return params; 47 14121 : } 48 : 49 4164 : ProjectionAux::ProjectionAux(const InputParameters & parameters) 50 : : AuxKernel(parameters), 51 4164 : _v(coupledValue("v")), 52 8328 : _source_variable(*getFieldVar("v", 0)), 53 8328 : _source_sys(_c_fe_problem.getSystem(coupledName("v"))), 54 8328 : _use_block_restriction_for_source(getParam<bool>("use_block_restriction_for_source")), 55 12492 : _elem_to_node_projection_weighting(getParam<MooseEnum>("elem_to_node_projection_weighting") 56 12492 : .getEnum<ElemToNodeProjectionWeighting>()) 57 : { 58 : // Output some messages to user 59 4164 : if (_source_variable.order() > _var.order()) 60 1523 : mooseInfo("Projection lowers order, please expect a loss of accuracy"); 61 4164 : } 62 : 63 : Real 64 12635935 : ProjectionAux::computeValue() 65 : { 66 12635935 : if (!isNodal() || (_source_variable.isNodal() && _source_variable.order() >= _var.order())) 67 12482399 : return _v[_qp]; 68 : // projecting continuous variable onto a nodal one 69 : // AND projecting from low order -> nodal higher order 70 191256 : else if (isNodal() && _source_variable.getContinuity() != DISCONTINUOUS && 71 37720 : _source_variable.getContinuity() != SIDE_DISCONTINUOUS) 72 75440 : return _source_sys.point_value( 73 75440 : _source_variable.number(), *_current_node, elemOnNodeVariableIsDefinedOn()); 74 : // Handle discontinuous elemental variable projection into a nodal variable 75 : else 76 : { 77 : // Custom projection rule : use nodal values, if discontinuous the one coming from each element, 78 : // weighted by element volumes 79 : // First, find all the elements that this node is part of 80 115816 : const auto & elem_ids = libmesh_map_find(_mesh.nodeToElemMap(), _current_node->id()); 81 : 82 : // Get the neighbor element centroid values & element volumes 83 115816 : Real sum_weighted_values = 0; 84 115816 : Real sum_weights = 0; 85 115816 : _elem_dims.clear(); 86 514872 : for (const auto id : elem_ids) 87 : { 88 399056 : const auto * const elem = _mesh.elemPtr(id); 89 399056 : const auto block_id = elem->subdomain_id(); 90 798112 : if (_source_variable.hasBlocks(block_id) && 91 399056 : (!_use_block_restriction_for_source || hasBlocks(block_id))) 92 : { 93 398864 : if (_elem_to_node_projection_weighting == ProjectionAux::VOLUME) 94 398864 : _elem_dims.insert(elem->dim()); 95 : const auto elem_weight = 96 398864 : _elem_to_node_projection_weighting == ProjectionAux::VOLUME ? elem->volume() : 1.; 97 398864 : sum_weighted_values += 98 398864 : _source_sys.point_value(_source_variable.number(), *_current_node, elem) * elem_weight; 99 398864 : sum_weights += elem_weight; 100 : } 101 : } 102 115816 : if (sum_weights == 0) 103 0 : mooseError("Did not find a valid source variable value for node: ", *_current_node); 104 115816 : if ((_elem_to_node_projection_weighting == ProjectionAux::VOLUME) && (_elem_dims.size() > 1)) 105 0 : mooseError("We should not use multiple element dimensions when computing the volume weighted " 106 : "projection as the units do not make sense"); 107 115816 : return sum_weighted_values / sum_weights; 108 : } 109 : } 110 : 111 : const Elem * 112 37720 : ProjectionAux::elemOnNodeVariableIsDefinedOn() const 113 : { 114 37720 : for (const auto & elem_id : _mesh.nodeToElemMap().find(_current_node->id())->second) 115 : { 116 37720 : const auto & elem = _mesh.elemPtr(elem_id); 117 37720 : const auto block_id = elem->subdomain_id(); 118 75440 : if (_source_variable.hasBlocks(block_id) && 119 37720 : (!_use_block_restriction_for_source || hasBlocks(block_id))) 120 37720 : return elem; 121 : } 122 0 : mooseError("Source variable is not defined everywhere the target variable is"); 123 : }