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 234 : AverageGrainVolume::validParams() 23 : { 24 234 : InputParameters params = GeneralPostprocessor::validParams(); 25 234 : 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 468 : params.addParam<UserObjectName>("feature_counter", 36 : "The FeatureFloodCount UserObject to get values from."); 37 : 38 : // Mode 2: Calculate grain volumes adirectly 39 468 : params.addCoupledVarWithAutoBuild( 40 : "variable", "var_name_base", "op_num", "Array of coupled variables"); 41 468 : params.addParam<unsigned int>("grain_num", "number of grains to create"); 42 234 : return params; 43 0 : } 44 : 45 117 : AverageGrainVolume::AverageGrainVolume(const InputParameters & parameters) 46 : : GeneralPostprocessor(parameters), 47 : Coupleable(this, false), 48 : MooseVariableDependencyInterface(this), 49 234 : _mesh(_subproblem.mesh()), 50 117 : _assembly(_subproblem.assembly(0, _sys.number())), 51 117 : _q_point(_assembly.qPoints()), 52 117 : _qrule(_assembly.qRule()), 53 117 : _JxW(_assembly.JxW()), 54 117 : _coord(_assembly.coordTransformation()), 55 117 : _feature_counter(isParamValid("feature_counter") 56 223 : ? &getUserObject<FeatureFloodCount>("feature_counter") 57 117 : : nullptr) 58 : { 59 117 : if (!_feature_counter) 60 : { 61 44 : if (isParamValid("variable") && isParamValid("grain_num")) 62 : { 63 11 : auto num_coupled_vars = coupledComponents("variable"); 64 22 : 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 11 : _vals = coupledValues("variable"); 69 : 70 11 : _feature_volumes.resize(num_coupled_vars); 71 : 72 : // Build a reflexive map (ops map to grains directly) 73 11 : _static_var_to_feature.resize(num_coupled_vars); 74 55 : for (MooseIndex(_static_var_to_feature) i = 0; i < num_coupled_vars; ++i) 75 44 : _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 106 : _vals.reserve(coupled_vars.size()); 84 : 85 378 : for (auto & coupled_var : coupled_vars) 86 272 : _vals.emplace_back(&coupled_var->sln()); 87 : 88 106 : addMooseVariableDependency(_feature_counter->getFECoupledVars()); 89 : } 90 117 : } 91 : 92 : void 93 209 : 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 209 : if (_feature_counter) 99 184 : num_features = _feature_counter->getTotalFeatureCount(); 100 : 101 209 : _feature_volumes.assign(num_features, 0); 102 209 : } 103 : 104 : void 105 209 : AverageGrainVolume::execute() 106 : { 107 : auto num_features = _feature_volumes.size(); 108 363138 : for (const auto & elem : _mesh.getMesh().active_local_element_ptr_range()) 109 : { 110 181360 : _fe_problem.prepare(elem, 0); 111 181360 : _fe_problem.reinitElem(elem, 0); 112 : 113 : const std::vector<unsigned int> & var_to_feature_ptr = 114 181360 : _feature_counter ? _feature_counter->getVarToFeatureVector(elem->id()) 115 : : _static_var_to_feature; 116 : 117 181360 : accumulateVolumes(var_to_feature_ptr, num_features); 118 209 : } 119 209 : } 120 : 121 : void 122 181360 : AverageGrainVolume::accumulateVolumes(const std::vector<unsigned int> & var_to_features, 123 : std::size_t libmesh_dbg_var(num_features)) 124 : { 125 881360 : for (MooseIndex(var_to_features) var_index = 0; var_index < var_to_features.size(); ++var_index) 126 : { 127 : // Only sample "active" variables 128 700000 : 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 289033 : auto integral_value = computeIntegral(var_index); 133 : 134 289033 : _feature_volumes[feature_id] += integral_value; 135 : } 136 : } 137 181360 : } 138 : 139 : Real 140 289033 : AverageGrainVolume::computeIntegral(std::size_t var_index) const 141 : { 142 : Real sum = 0; 143 : 144 1445165 : for (unsigned int qp = 0; qp < _qrule->n_points(); ++qp) 145 1156132 : sum += _JxW[qp] * _coord[qp] * (*_vals[var_index])[qp]; 146 : 147 289033 : return sum; 148 : } 149 : 150 : void 151 209 : AverageGrainVolume::finalize() 152 : { 153 209 : gatherSum(_feature_volumes); 154 209 : } 155 : 156 : Real 157 209 : AverageGrainVolume::getValue() const 158 : { 159 : Real total_volume = 0; 160 1869 : for (auto & volume : _feature_volumes) 161 1660 : total_volume += volume; 162 : 163 : unsigned int active_features = 164 209 : _feature_counter ? _feature_counter->getNumberActiveFeatures() : _feature_volumes.size(); 165 : 166 209 : return total_volume / active_features; 167 : }