LCOV - code coverage report
Current view: top level - src/optimizationreporters - ParameterMeshOptimization.C (source / functions) Hit Total Coverage
Test: idaholab/moose optimization: #31405 (292dce) with base fef103 Lines: 91 97 93.8 %
Date: 2025-09-04 07:54:57 Functions: 4 4 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 "ParameterMeshOptimization.h"
      11             : 
      12             : #include "AddVariableAction.h"
      13             : #include "ParameterMesh.h"
      14             : #include "libmesh/string_to_enum.h"
      15             : 
      16             : using namespace libMesh;
      17             : 
      18             : registerMooseObject("OptimizationApp", ParameterMeshOptimization);
      19             : 
      20             : InputParameters
      21         300 : ParameterMeshOptimization::validParams()
      22             : {
      23         300 :   InputParameters params = GeneralOptimization::validParams();
      24             : 
      25         300 :   params.addClassDescription(
      26             :       "Computes objective function, gradient and contains reporters for communicating between "
      27             :       "optimizeSolve and subapps using mesh-based parameter definition.");
      28             : 
      29         600 :   params.addRequiredParam<std::vector<FileName>>(
      30             :       "parameter_meshes", "Exodus file containing meshes describing parameters.");
      31             : 
      32         300 :   const auto family = AddVariableAction::getNonlinearVariableFamilies();
      33         300 :   MultiMooseEnum families(family.getRawNames(), "LAGRANGE");
      34         600 :   params.addParam<MultiMooseEnum>(
      35             :       "parameter_families",
      36             :       families,
      37             :       "Specifies the family of FE shape functions for each group of parameters. If a single value "
      38             :       "is "
      39             :       "specified, then that value is used for all groups of parameters.");
      40         300 :   const auto order = AddVariableAction::getNonlinearVariableOrders();
      41         300 :   MultiMooseEnum orders(order.getRawNames(), "FIRST");
      42         600 :   params.addParam<MultiMooseEnum>(
      43             :       "parameter_orders",
      44             :       orders,
      45             :       "Specifies the order of FE shape functions for each group of parameters. If a single value "
      46             :       "is "
      47             :       "specified, then that value is used for all groups of parameters.");
      48             : 
      49         600 :   params.addParam<unsigned int>(
      50         600 :       "num_parameter_times", 1, "The number of time points the parameters represent.");
      51             : 
      52         600 :   params.addParam<std::vector<std::string>>(
      53             :       "initial_condition_mesh_variable",
      54             :       "Name of variable on parameter mesh to use as initial condition.");
      55         600 :   params.addParam<std::vector<std::string>>(
      56             :       "lower_bound_mesh_variable", "Name of variable on parameter mesh to use as lower bound.");
      57         600 :   params.addParam<std::vector<std::string>>(
      58             :       "upper_bound_mesh_variable", "Name of variable on parameter mesh to use as upper bound.");
      59         600 :   params.addParam<std::vector<unsigned int>>(
      60             :       "exodus_timesteps_for_parameter_mesh_variable",
      61             :       "Timesteps to read all parameter group bounds and initial conditions from Exodus mesh.  The "
      62             :       "options are to give no timestep, a single timestep or \"num_parameter_times\" timesteps.  "
      63             :       "No timestep results in the final timestep from the mesh being used.  A single timestep "
      64             :       "results in values at that timestep being used for all timesteps.  \"num_parameter_times\" "
      65             :       "timesteps results in values from the mesh at those steps being used.  The same timesteps "
      66             :       "are used for all parameter groups and all meshes, the capability to define different "
      67             :       "timesteps for different meshes is not supported.");
      68             : 
      69         300 :   return params;
      70         300 : }
      71             : 
      72         150 : ParameterMeshOptimization::ParameterMeshOptimization(const InputParameters & parameters)
      73         150 :   : GeneralOptimization(parameters)
      74             : {
      75         150 : }
      76             : 
      77             : std::vector<Real>
      78         200 : ParameterMeshOptimization::parseExodusData(const std::vector<unsigned int> & exodus_timestep,
      79             :                                            const ParameterMesh & pmesh,
      80             :                                            const std::string & mesh_var_name,
      81             :                                            unsigned int ntimes) const
      82             : {
      83         200 :   unsigned int num_cont_params = pmesh.size() * ntimes;
      84             :   std::vector<Real> parsed_data;
      85             :   // read from mesh
      86             : 
      87         564 :   for (auto const & step : exodus_timestep)
      88             :   {
      89         730 :     std::vector<Real> data = pmesh.getParameterValues(mesh_var_name, step);
      90         364 :     parsed_data.insert(parsed_data.end(), data.begin(), data.end());
      91         364 :   }
      92         198 :   if (parsed_data.size() != num_cont_params)
      93           0 :     mooseError("Number of parameters assigned by ",
      94             :                mesh_var_name,
      95             :                " is not equal to the number of parameters on the mesh.  Mesh contains ",
      96             :                num_cont_params,
      97             :                " parameters and ",
      98             :                mesh_var_name,
      99             :                " assigned ",
     100           0 :                parsed_data.size(),
     101             :                " parameters.");
     102             : 
     103         198 :   return parsed_data;
     104           0 : }
     105             : 
     106             : void
     107         150 : ParameterMeshOptimization::setICsandBounds()
     108             : {
     109         600 :   if ((isParamValid("num_values_name") || isParamValid("num_values")))
     110           0 :     paramError("num_values_name or num_values should not be used with ParameterMeshOptimization. "
     111             :                "Instead the number of dofs is set by the parameter meshes.");
     112             : 
     113         150 :   _nvalues.resize(_nparams, 0);
     114             :   // Fill the mesh information
     115         150 :   const auto & meshes = getParam<std::vector<FileName>>("parameter_meshes");
     116         150 :   const auto & families = getParam<MultiMooseEnum>("parameter_families");
     117         150 :   const auto & orders = getParam<MultiMooseEnum>("parameter_orders");
     118         300 :   const auto & ntimes = getParam<unsigned int>("num_parameter_times");
     119             : 
     120             :   // Fill exodus parameter bounds and IC information
     121             :   std::vector<std::string> initial_condition_mesh_variable;
     122             :   std::vector<std::string> lower_bound_mesh_variable;
     123             :   std::vector<std::string> upper_bound_mesh_variable;
     124         300 :   if (isParamValid("initial_condition_mesh_variable"))
     125             :     initial_condition_mesh_variable =
     126         168 :         getParam<std::vector<std::string>>("initial_condition_mesh_variable");
     127         300 :   if (isParamValid("lower_bound_mesh_variable"))
     128         111 :     lower_bound_mesh_variable = getParam<std::vector<std::string>>("lower_bound_mesh_variable");
     129         300 :   if (isParamValid("upper_bound_mesh_variable"))
     130         153 :     upper_bound_mesh_variable = getParam<std::vector<std::string>>("upper_bound_mesh_variable");
     131             : 
     132             :   std::vector<unsigned int> exodus_timestep;
     133         300 :   if (isParamValid("exodus_timesteps_for_parameter_mesh_variable"))
     134             :     exodus_timestep =
     135          99 :         getParam<std::vector<unsigned int>>("exodus_timesteps_for_parameter_mesh_variable");
     136             :   else // get last timestep in file
     137         117 :     exodus_timestep = {std::numeric_limits<unsigned int>::max()};
     138             : 
     139             :   // now do a bunch of error checking
     140             :   // Size checks for data
     141         150 :   if (meshes.size() != _nparams)
     142           2 :     paramError("parameter_meshes",
     143             :                "There must be a mesh associated with each group of parameters.");
     144         148 :   if (families.size() > 1 && families.size() != _nparams)
     145           2 :     paramError("parameter_families",
     146             :                "There must be a family associated with each group of parameters.");
     147         146 :   if (orders.size() > 1 && orders.size() != _nparams)
     148           2 :     paramError("parameter_orders",
     149             :                "There must be an order associated with each group of parameters.");
     150             : 
     151             :   // error checking that initial conditions and bounds are only read from a single location
     152         400 :   if (isParamValid("initial_condition_mesh_variable") && isParamValid("initial_condition"))
     153           0 :     paramError("initial_condition_mesh_variable",
     154             :                "Initial conditions for all parameter groups can only be defined by "
     155             :                "initial_condition_mesh_variable or "
     156             :                "initial_condition but not both.");
     157         362 :   else if (isParamValid("lower_bound_mesh_variable") && isParamValid("lower_bounds"))
     158           2 :     paramError(
     159             :         "lower_bound_mesh_variable",
     160             :         "Lower bounds for all parameter groups can only be defined by lower_bound_mesh_variable or "
     161             :         "lower_bounds but not both.");
     162         382 :   else if (isParamValid("upper_bound_mesh_variable") && isParamValid("upper_bounds"))
     163           0 :     paramError(
     164             :         "upper_bound_mesh_variable",
     165             :         "Upper bounds for all parameter groups can only be defined by upper_bound_mesh_variable or "
     166             :         "upper_bounds but not both.");
     167             : 
     168             :   // Make sure they did not specify too many timesteps
     169         426 :   if (isParamValid("exodus_timesteps_for_parameter_mesh_variable") &&
     170         241 :       (!isParamValid("lower_bound_mesh_variable") + !isParamValid("upper_bound_mesh_variable") +
     171         239 :            !isParamValid("initial_condition_mesh_variable") ==
     172             :        3))
     173           2 :     paramError("\"exodus_timesteps_for_parameter_mesh_variable\" should only be specified if "
     174             :                "reading values from a mesh.");
     175         140 :   else if (exodus_timestep.size() != ntimes && exodus_timestep.size() != 1)
     176           2 :     paramError("exodus_timesteps_for_parameter_mesh_variable",
     177             :                "Number of timesteps to read mesh data specified by "
     178             :                "\"exodus_timesteps_for_parameter_mesh_variable\" incorrect. "
     179             :                "\"exodus_timesteps_for_parameter_mesh_variable\" can specify a single timestep or "
     180             :                "\"num_parameter_times\" timesteps.");
     181             : 
     182         138 :   _ndof = 0;
     183         304 :   for (const auto & param_id : make_range(_nparams))
     184             :   {
     185             :     // store off all the variable names that you might want to read from the mesh
     186             :     std::vector<std::string> var_names;
     187         348 :     if (isParamValid("initial_condition_mesh_variable"))
     188          83 :       var_names.push_back(initial_condition_mesh_variable[param_id]);
     189         348 :     if (isParamValid("lower_bound_mesh_variable"))
     190          51 :       var_names.push_back(lower_bound_mesh_variable[param_id]);
     191         348 :     if (isParamValid("upper_bound_mesh_variable"))
     192          76 :       var_names.push_back(upper_bound_mesh_variable[param_id]);
     193             : 
     194         174 :     const std::string family = families.size() > 1 ? families[param_id] : families[0];
     195         174 :     const std::string order = orders.size() > 1 ? orders[param_id] : orders[0];
     196         174 :     const FEType fetype(Utility::string_to_enum<Order>(order),
     197         174 :                         Utility::string_to_enum<FEFamily>(family));
     198             : 
     199         174 :     ParameterMesh pmesh(fetype, meshes[param_id], var_names);
     200         170 :     _nvalues[param_id] = pmesh.size() * ntimes;
     201         170 :     _ndof += _nvalues[param_id];
     202             : 
     203             :     // read and assign initial conditions
     204             :     std::vector<Real> initial_condition;
     205         340 :     if (isParamValid("initial_condition_mesh_variable"))
     206         162 :       initial_condition = parseExodusData(
     207             :           exodus_timestep, pmesh, initial_condition_mesh_variable[param_id], ntimes);
     208             :     else
     209         263 :       initial_condition = parseInputData("initial_condition", 0, param_id);
     210             : 
     211         168 :     _parameters[param_id]->assign(initial_condition.begin(), initial_condition.end());
     212             : 
     213             :     // read and assign lower bound
     214             :     std::vector<Real> lower_bound;
     215         336 :     if (isParamValid("lower_bound_mesh_variable"))
     216             :       lower_bound =
     217          92 :           parseExodusData(exodus_timestep, pmesh, lower_bound_mesh_variable[param_id], ntimes);
     218             :     else
     219         363 :       lower_bound = parseInputData("lower_bounds", std::numeric_limits<Real>::lowest(), param_id);
     220             : 
     221         166 :     _lower_bounds.insert(_lower_bounds.end(), lower_bound.begin(), lower_bound.end());
     222             : 
     223             :     // read and assign upper bound
     224             :     std::vector<Real> upper_bound;
     225         332 :     if (isParamValid("upper_bound_mesh_variable"))
     226             :       upper_bound =
     227         144 :           parseExodusData(exodus_timestep, pmesh, upper_bound_mesh_variable[param_id], ntimes);
     228             :     else
     229         282 :       upper_bound = parseInputData("upper_bounds", std::numeric_limits<Real>::max(), param_id);
     230             : 
     231         166 :     _upper_bounds.insert(_upper_bounds.end(), upper_bound.begin(), upper_bound.end());
     232             : 
     233             :     // resize gradient vector to be filled later
     234         166 :     _gradients[param_id]->resize(_nvalues[param_id]);
     235         332 :   }
     236         130 : }

Generated by: LCOV version 1.14