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 "AverageGrainVolume.h" 11 : #include "FeatureFloodCount.h" 12 : #include "MooseMesh.h" 13 : #include "Assembly.h" 14 : #include "MooseVariable.h" 15 : #include "SystemBase.h" 16 : 17 : #include "libmesh/quadrature.h" 18 : 19 : registerMooseObject("PhaseFieldApp", AverageGrainVolume); 20 : 21 : InputParameters 22 170 : AverageGrainVolume::validParams() 23 : { 24 170 : InputParameters params = GeneralPostprocessor::validParams(); 25 170 : params.addClassDescription("Calculate average grain area in a polycrystal"); 26 : 27 : /** 28 : * This object has two modes of operation: It can be used with the FeatureFloodCount object 29 : * (recommended) to get the active grain on element information needed to calculate volumes. 30 : * It can also work on small polycrystals where an equal number of grains and order parameters 31 : * are used in the simulation. This dual-functionality creates two separate code paths 32 : * and parameter sets. 33 : */ 34 : // Mode 1: Use the GrainTracker 35 340 : params.addParam<UserObjectName>("feature_counter", 36 : "The FeatureFloodCount UserObject to get values from."); 37 : 38 : // Mode 2: Calculate grain volumes adirectly 39 340 : params.addCoupledVarWithAutoBuild( 40 : "variable", "var_name_base", "op_num", "Array of coupled variables"); 41 340 : params.addParam<unsigned int>("grain_num", "number of grains to create"); 42 170 : return params; 43 0 : } 44 : 45 85 : AverageGrainVolume::AverageGrainVolume(const InputParameters & parameters) 46 : : GeneralPostprocessor(parameters), 47 : Coupleable(this, false), 48 : MooseVariableDependencyInterface(this), 49 170 : _mesh(_subproblem.mesh()), 50 85 : _assembly(_subproblem.assembly(0, _sys.number())), 51 85 : _q_point(_assembly.qPoints()), 52 85 : _qrule(_assembly.qRule()), 53 85 : _JxW(_assembly.JxW()), 54 85 : _coord(_assembly.coordTransformation()), 55 85 : _feature_counter(isParamValid("feature_counter") 56 163 : ? &getUserObject<FeatureFloodCount>("feature_counter") 57 85 : : nullptr) 58 : { 59 85 : if (!_feature_counter) 60 : { 61 28 : if (isParamValid("variable") && isParamValid("grain_num")) 62 : { 63 7 : auto num_coupled_vars = coupledComponents("variable"); 64 14 : if (num_coupled_vars != getParam<unsigned int>("grain_num")) 65 0 : mooseError("The number of grains must match the number of OPs if a feature_counter is not " 66 : "supplied"); 67 : 68 7 : _vals = coupledValues("variable"); 69 : 70 7 : _feature_volumes.resize(num_coupled_vars); 71 : 72 : // Build a reflexive map (ops map to grains directly) 73 7 : _static_var_to_feature.resize(num_coupled_vars); 74 35 : for (MooseIndex(_static_var_to_feature) i = 0; i < num_coupled_vars; ++i) 75 28 : _static_var_to_feature[i] = i; 76 : } 77 : else 78 0 : mooseError("Must supply either a feature_counter object or coupled variables and grain_num"); 79 : } 80 : else 81 : { 82 : const auto & coupled_vars = _feature_counter->getCoupledVars(); 83 78 : _vals.reserve(coupled_vars.size()); 84 : 85 270 : for (auto & coupled_var : coupled_vars) 86 192 : _vals.emplace_back(&coupled_var->sln()); 87 : 88 78 : addMooseVariableDependency(_feature_counter->getFECoupledVars()); 89 : } 90 85 : } 91 : 92 : void 93 159 : AverageGrainVolume::initialize() 94 : { 95 : auto num_features = _feature_volumes.size(); 96 : 97 : // When using FeatureFloodCount, the number of grains may not be fixed. Resize as appropriate 98 159 : if (_feature_counter) 99 140 : num_features = _feature_counter->getTotalFeatureCount(); 100 : 101 159 : _feature_volumes.assign(num_features, 0); 102 159 : } 103 : 104 : void 105 159 : AverageGrainVolume::execute() 106 : { 107 : auto num_features = _feature_volumes.size(); 108 300046 : for (const auto & elem : _mesh.getMesh().active_local_element_ptr_range()) 109 : { 110 149864 : _fe_problem.prepare(elem, 0); 111 149864 : _fe_problem.reinitElem(elem, 0); 112 : 113 : const std::vector<unsigned int> & var_to_feature_ptr = 114 149864 : _feature_counter ? _feature_counter->getVarToFeatureVector(elem->id()) 115 : : _static_var_to_feature; 116 : 117 149864 : accumulateVolumes(var_to_feature_ptr, num_features); 118 159 : } 119 159 : } 120 : 121 : void 122 149864 : AverageGrainVolume::accumulateVolumes(const std::vector<unsigned int> & var_to_features, 123 : std::size_t libmesh_dbg_var(num_features)) 124 : { 125 721976 : for (MooseIndex(var_to_features) var_index = 0; var_index < var_to_features.size(); ++var_index) 126 : { 127 : // Only sample "active" variables 128 572112 : if (var_to_features[var_index] != FeatureFloodCount::invalid_id) 129 : { 130 : auto feature_id = var_to_features[var_index]; 131 : mooseAssert(feature_id < num_features, "Feature ID out of range"); 132 239110 : auto integral_value = computeIntegral(var_index); 133 : 134 239110 : _feature_volumes[feature_id] += integral_value; 135 : } 136 : } 137 149864 : } 138 : 139 : Real 140 239110 : AverageGrainVolume::computeIntegral(std::size_t var_index) const 141 : { 142 : Real sum = 0; 143 : 144 1195550 : for (unsigned int qp = 0; qp < _qrule->n_points(); ++qp) 145 956440 : sum += _JxW[qp] * _coord[qp] * (*_vals[var_index])[qp]; 146 : 147 239110 : return sum; 148 : } 149 : 150 : void 151 159 : AverageGrainVolume::finalize() 152 : { 153 159 : gatherSum(_feature_volumes); 154 159 : } 155 : 156 : Real 157 159 : AverageGrainVolume::getValue() const 158 : { 159 : Real total_volume = 0; 160 1375 : for (auto & volume : _feature_volumes) 161 1216 : total_volume += volume; 162 : 163 : unsigned int active_features = 164 159 : _feature_counter ? _feature_counter->getNumberActiveFeatures() : _feature_volumes.size(); 165 : 166 159 : return total_volume / active_features; 167 : }