https://mooseframework.inl.gov
GeneralSensorPostprocessor.C
Go to the documentation of this file.
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 #include <vector>
10 #include <cmath>
11 #include <algorithm>
12 #include <numeric>
13 
15 #include "Function.h"
16 #include "MooseRandom.h"
17 #include "LinearInterpolation.h"
18 #include "SplineInterpolation.h"
19 
21 
24 {
26  params.addRequiredParam<PostprocessorName>("input_signal", "The input signal postprocessor");
27  params.addParam<FunctionName>(
28  "drift_function", 0.0, "Drift function describing signal drift over time");
29  params.addParam<Real>("vector_size", 1000000000.0, "The maximum size of vector to be saved");
30  params.addClassDescription("This is a GeneralSensorPostprocessor, and functions as a base class "
31  "for other sensor postprocessors");
32  params.addParam<FunctionName>(
33  "efficiency_function", 0.8, "Efficiency function describing efficiency over time");
34  params.addParam<FunctionName>(
35  "noise_std_dev_function",
36  0.5,
37  "Standard deviation of noise function describing noise standard deviation over time");
38  params.addParam<FunctionName>(
39  "signalToNoise_function", 0.2, "Signal to noise ratio for the modeled sensor");
40  params.addParam<FunctionName>(
41  "delay_function", 0.1, "Delay function describing the delay over time");
42  params.addParam<FunctionName>(
43  "uncertainty_std_dev_function",
44  0.1,
45  "Standard deviation of uncertainty function describing uncertainty std dev over time");
46  params.addParam<FunctionName>("R_function", 1, "The function R for the integration term.");
47  params.addParam<Real>("proportional_weight", 1, "The weight assigned to the proportional term");
48  params.addParam<Real>("integral_weight", 0, "The weight assigned to the integral term");
49  params.addParam<unsigned int>("seed", 1, "Seed for the random number generator");
50  return params;
51 }
52 
54  : GeneralPostprocessor(parameters),
55  _input_signal(getPostprocessorValue("input_signal")),
56  _drift_function(getFunction("drift_function")),
57  _vector_size(getParam<Real>("vector_size")),
58  _pp_old(getPostprocessorValueOld("input_signal")),
59  _efficiency_function(getFunction("efficiency_function")),
60  _noise_std_dev_function(getFunction("noise_std_dev_function")),
61  _delay_function(getFunction("delay_function")),
62  _signalToNoise_function(getFunction("signalToNoise_function")),
63  _uncertainty_std_dev_function(getFunction("uncertainty_std_dev_function")),
64  _R_function(getFunction("R_function")),
65  _proportional_weight(getParam<Real>("proportional_weight")),
66  _integral_weight(getParam<Real>("integral_weight")),
67  _time_values(declareRestartableData<std::vector<Real>>("time_values")),
68  _input_signal_values(declareRestartableData<std::vector<Real>>("input_signal_values")),
69  _integrand(declareRestartableData<std::vector<Real>>("integrand")),
70  _R_function_values(declareRestartableData<std::vector<Real>>("R_function_values")),
71  _t_step_old(declareRestartableData<int>("gsp_t_step_old", -1)),
72  _seed(getParam<unsigned int>("seed")),
73  _delay_value(0) // Initialize delay_value at 0
74 {
75 }
76 
77 void
79 {
80  Real drift_value = _drift_function.value(_t);
81  Real efficiency_value = _efficiency_function.value(_t);
82  Real signalToNoise_value = _signalToNoise_function.value(_t);
83  // setting seed for random number generator
84  _rng.seed(_seed);
85  Real noise_std_dev = _noise_std_dev_function.value(_t);
86  Real noise_value = _rng.randNormal(0, noise_std_dev);
87  Real uncertainty_std_dev = _uncertainty_std_dev_function.value(_t);
88  Real uncertainty_value = _rng.randNormal(0, uncertainty_std_dev);
89  // Added line to calculate delay_value from the delay function
91 
92  // if the problem is steady-state
93  if (!_fe_problem.isTransient())
94  {
95  // output
96  _sensor_value = drift_value +
97  efficiency_value * (_input_signal + signalToNoise_value * noise_value) +
98  uncertainty_value;
99  }
100 
101  // if the problem is transient
102  else
103  {
104  // Remove last element if we are repeating the timestep
105  mooseAssert(_t_step_old <= _t_step,
106  "The old time step needs to be behind or the same as the current time step.");
107  if (_t_step_old == _t_step)
108  {
109  _time_values.pop_back();
110  _input_signal_values.pop_back();
111  _integrand.pop_back();
112  _R_function_values.pop_back();
113  }
114 
115  _time_values.push_back(_t);
117 
118  // Check if the size is greater than _vector_size
120  {
121  // Remove the first 10 elements if size is larger
122  _time_values.erase(_time_values.begin(), _time_values.begin() + 10);
124  }
125  Real _input_signal_delayed = getDelayedInputSignal();
126 
127  // computing integral term
128  Real term_for_integration = _input_signal + signalToNoise_value * noise_value;
129  _integrand.push_back(term_for_integration);
131 
132  // output
133  Real proportional_value = _input_signal_delayed + signalToNoise_value * noise_value;
134  _sensor_value = drift_value +
135  efficiency_value * (_proportional_weight * proportional_value +
137  uncertainty_value;
138 
139  // Update old time step
141  }
142 }
143 
146 {
147  return _sensor_value;
148 }
149 
150 std::vector<Real>
151 GeneralSensorPostprocessor::elementwiseMultiply(std::vector<Real> & vec1, std::vector<Real> & vec2)
152 {
153  // Ensure both vectors have the same size
154  mooseAssert(vec1.size() == vec2.size(),
155  "Vectors must have the same size for element-wise multiplication.");
156  // Create a result vector
157  std::vector<Real> result;
158  // Perform element-wise multiplication
159  result.reserve(vec1.size());
160  for (const auto i : index_range(vec1))
161  result.push_back(vec1[i] * vec2[i]);
162  return result;
163 }
164 
165 Real
167 {
168  // delayed input signal
169  Real t_desired = _t - _delay_value;
170  Real input_signal_delayed;
171 
172  if (t_desired < _time_values[0])
173  input_signal_delayed = 0;
174 
175  // Modified cases where desired time isin the time value list
176  else if (t_desired == _time_values[0])
177  input_signal_delayed = _input_signal_values[0];
178 
179  // linear interpolation
180  else if (t_desired > _time_values[0] && t_desired <= _t && t_desired >= _t - _dt)
181  input_signal_delayed = _input_signal + (t_desired - _t) * (_pp_old - _input_signal) / (-_dt);
182 
183  else if (t_desired > _time_values[0] && t_desired < _t - _dt)
184  {
185  LinearInterpolation time_and_input_signal(_time_values, _input_signal_values);
186  input_signal_delayed = time_and_input_signal.sample(t_desired);
187  }
188 
189  else
190  mooseError("Unhandled case in interpolation values.");
191 
192  return input_signal_delayed;
193 }
194 
195 vector<Real>
197 {
199  return _R_function_values;
200 }
201 
202 Real
203 GeneralSensorPostprocessor::getIntegral(std::vector<Real> integrand)
204 {
205  Real integration_value;
206  getRVector();
207  // calculate the total integrand vector including previous integrand and exponential terms
209 
210  // if there are more than two datapoints, do simpson's 3/8 rule for integration
211  // else do trapezoidal rule
212  if (_time_values.size() > 2)
213  {
215  // number of intervals
216  Real n;
217 
218  // if number of datapoints is less than 30, use spline interpolation to get 30 intervals
219  if (_time_values.size() < 30)
220  n = 30;
221  else
222  {
223  n = _time_values.size();
224  // if interval is not a multiple of 3, make it
225  while (static_cast<int>(n) % 3 != 0)
226  n = n + 1;
227  }
228 
229  Real h = (_time_values.back() - _time_values[0]) / n; // distance between time values
230  // time vector for simpson integration
231  vector<Real> time_vec_simp;
232  // integrand vector for simpson integration
233  vector<Real> integrand_vec_simp;
234 
235  for (Real i = 0; i < n + 1; i++)
236  {
237  Real new_time = _time_values[0] + i * h;
238  time_vec_simp.push_back(new_time);
239  Real new_integrand = spline.SplineInterpolation::sample(new_time);
240  integrand_vec_simp.push_back(new_integrand);
241  }
242 
243  // initialize integral with endpoints
244  integration_value = integrand_vec_simp[0] + integrand_vec_simp[n];
245 
246  // Sum for points not at endpoints
247  for (int i = 1; i < n; ++i)
248  {
249  if (i % 3 == 0)
250  // Every third point
251  integration_value += 2 * integrand_vec_simp[i];
252  else
253  integration_value += 3 * integrand_vec_simp[i];
254  }
255 
256  // Multiply by 3h/8
257  integration_value *= (3 * h) / 8.0;
258  }
259 
260  else
261  {
262  // performing integration by trapezoidal rule, not accurate
263  // LinearInterpolation object with two vectors
265  // integrate the vectors
266  integration_value = integral.integrate();
267  }
268 
269  return integration_value;
270 }
const Function & _signalToNoise_function
Signal to noise function.
std::vector< Real > & _input_signal_values
Input Signal vector for calculating delay.
std::vector< Real > elementwiseMultiply(std::vector< Real > &vec1, std::vector< Real > &vec2)
Function for element-wise multiplication of vectors.
void addParam(const std::string &name, const std::initializer_list< typename T::value_type > &value, const std::string &doc_string)
const Function & _uncertainty_std_dev_function
Uncertainty std dev function.
void seed(std::size_t i, unsigned int seed)
const Function & _efficiency_function
Efficiency function.
T sample(const T &x) const
virtual PostprocessorValue getValue() const override
virtual void initialize() override
void addRequiredParam(const std::string &name, const std::string &doc_string)
Real integrand(const Point &p)
Real randNormal(std::size_t i, Real mean, Real sigma)
const Function & _R_function
Function R for integration term.
registerMooseObject("MiscApp", GeneralSensorPostprocessor)
virtual vector< Real > getRVector()
Function to calculate R vector.
const Function & _drift_function
The drift function to be evaluated and returned.
static InputParameters validParams()
std::vector< Real > & _R_function_values
vector to store R function values
const Function & _noise_std_dev_function
Noise standard deviation function.
Real PostprocessorValue
Real getIntegral(std::vector< Real > integrand)
Function to calculate integral term.
std::vector< Real > & _integrand
Vector to store integrand data for numerical integration.
Real _sensor_value
for getValue() output
const Real _proportional_weight
A weighing factor for the proportional term.
int & _t_step_old
The last time step this object was executed on.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const PostprocessorValue & _pp_old
The old value of the postprocessor.
Real _delay_value
Variable to store delay value.
FEProblemBase & _fe_problem
const PostprocessorValue & _input_signal
A postprocessor used as the sensor input signal.
void mooseError(Args &&... args) const
void addClassDescription(const std::string &doc_string)
std::vector< Real > & _time_values
Time vector for calculating delay.
virtual bool isTransient() const override
GeneralSensorPostprocessor(const InputParameters &parameters)
virtual Real value(Real t, const Point &p) const
Real _integration_value
the output of the integrand
A generalized sensor Postprocessor.
const Real _integral_weight
A weighing factor for the integral term.
void ErrorVector unsigned int
auto index_range(const T &sizable)
const Real _vector_size
Size of vector to be stored.
const unsigned int _seed
To get fixed seed random numbers.
const Function & _delay_function
Delay function.
static InputParameters validParams()
Real getDelayedInputSignal()
Function to calculate delayed input signal.