LCOV - code coverage report
Current view: top level - src/postprocessors - AverageGrainVolume.C (source / functions) Hit Total Coverage
Test: idaholab/moose phase_field: #31405 (292dce) with base fef103 Lines: 62 65 95.4 %
Date: 2025-09-04 07:55:36 Functions: 8 8 100.0 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14