Skip to content
Permalink
Browse files

Merge pull request #13510 from bwspenc/least_squares_fix

Resolve issues with polynomial order truncation in LeastSquaresFit
  • Loading branch information...
permcody committed Jun 3, 2019
2 parents ee93ae3 + 559d4c4 commit 7f1c270edb0860facee368f029b9f65981bae1c2
@@ -10,7 +10,9 @@ This VectorPostprocessor is closely related to the [LeastSquaresFitHistory](/Lea

The vectors of values of the independent ($x$) and dependent ($y$) variables on which the least squares fit is performed are provided through another VectorPostprocessor, which must provide two equally-sized vectors of data upon which to operate. The name of this VectorPostprocesor is provided using the `vectorpostprocessor` parameter, and the names of the data vectors are provided with the `x_name` and `y_name` parameters. The vectors of data can be shifted and/or scaled through the use of optional parameters.

The user must define whether the output should be in the form of polynomial coefficients or samples using the `output` parameter. If the option to output polynommial coefficients is used, they are stored in a vector named `coefficients`. If samples are requested, the nam es of the sample vectors are the same as those of the data specified by `x_name` and `y_name`.
By default, if an insufficient number of points is provided in these data vectors, the order of the polynomial will be truncated to one less than the number of points. If the `truncate_order parameter is set to `false`, an error will be generated in this case.
The user must define whether the output should be in the form of polynomial coefficients or samples using the `output` parameter. If the option to output polynommial coefficients is used, they are stored in a vector named `coefficients`. If samples are requested, the names of the sample vectors are the same as those of the data specified by `x_name` and `y_name`.
!syntax parameters /VectorPostprocessors/LeastSquaresFit
@@ -12,6 +12,8 @@ The polynomial coefficients are stored in a set of vectors named `coef_0` throug

The vectors of values of the independent ($x$) and dependent ($y$) variables on which the least squares fit is performed are provided through another VectorPostprocessor, which must provide two equally-sized vectors of data upon which to operate. The name of this VectorPostprocesor is provided using the `vectorpostprocessor` parameter, and the names of the data vectors are provided with the `x_name` and `y_name` parameters. The vectors of data can be shifted and/or scaled through the use of optional parameters.

By default, if an insufficient number of points is provided in these data vectors, the order of the polynomial will be truncated to one less than the number of points. If the `truncate_order parameter is set to `false`, an error will be generated in this case.
!syntax parameters /VectorPostprocessors/LeastSquaresFitHistory
!syntax inputs /VectorPostprocessors/LeastSquaresFitHistory
@@ -26,9 +26,9 @@ class LeastSquaresFit : public GeneralVectorPostprocessor
{
public:
/**
* Class constructor
* @param parameters The input parameters
*/
* Class constructor
* @param parameters The input parameters
*/
LeastSquaresFit(const InputParameters & parameters);

/**
@@ -46,15 +46,19 @@ class LeastSquaresFit : public GeneralVectorPostprocessor
VectorPostprocessorName _vpp_name;

/// The order of the polynomial fit to be performed
unsigned int _order;
const unsigned int _order;

/// Whether to truncate the polynomial order if an insufficient number of points is provided
const bool _truncate_order;

/// The name of the variables storing the x, y data
const std::string _x_name;
const std::string _y_name;

/// The variables with the x, y data to be fit
///@{ The variables with the x, y data to be fit
const VectorPostprocessorValue & _x_values;
const VectorPostprocessorValue & _y_values;
///@}

/// The type of output
const MooseEnum _output_type;
@@ -73,13 +77,15 @@ class LeastSquaresFit : public GeneralVectorPostprocessor
bool _have_sample_x_min;
bool _have_sample_x_max;

/// The min and max x values for sampling
///@{ The min and max x values for sampling
Real _sample_x_min;
Real _sample_x_max;
///@}

/// The variables used to write out samples of the least squares fit
///@{ The variables used to write out samples of the least squares fit
VectorPostprocessorValue * _sample_x;
VectorPostprocessorValue * _sample_y;
///@}

/// The variable used to write out the coefficients of the fit
VectorPostprocessorValue * _coeffs;
@@ -47,15 +47,19 @@ class LeastSquaresFitHistory : public GeneralVectorPostprocessor
VectorPostprocessorName _vpp_name;

/// The order of the polynomial fit to be performed
unsigned int _order;
const unsigned int _order;

/// Whether to truncate the polynomial order if an insufficient number of points is provided
const bool _truncate_order;

/// The name of the variables storing the x, y data
const std::string _x_name;
const std::string _y_name;

/// The variables with the x, y data to be fit
///@{ The variables with the x, y data to be fit
const VectorPostprocessorValue & _x_values;
const VectorPostprocessorValue & _y_values;
///@}

///@{ Values used to scale and or shift x and y data
const Real _x_scale;
@@ -9,8 +9,11 @@

#include "PolynomialFit.h"

#include "MooseError.h"

// C++ includes
#include <fstream>
#include <algorithm>

int PolynomialFit::_file_number = 0;

@@ -20,21 +23,15 @@ PolynomialFit::PolynomialFit(const std::vector<Real> & x,
bool truncate_order)
: LeastSquaresFitBase(x, y), _order(order), _truncate_order(truncate_order)
{
if (_truncate_order) // && (_x.size() / 10) < _order)
if (_x.size() == 0)
mooseError("PolynomialFit does not allow empty input vectors");
if (_truncate_order)
{
if (_x.size() == 1)
_order = 0;
else
{
_order = (_x.size() / 10) + 1;

if (_order > order)
_order = order;
}
if (_x.size() <= _order)
_order = _x.size() - 1;
}
else if (_x.size() < order)
throw std::domain_error(
"Polynomial Fit requires an order less than the size of the input vector");
else if (_x.size() <= order)
mooseError("PolynomialFit requires an order less than the size of the input vector");

_num_coeff = _order + 1;
}
@@ -25,6 +25,11 @@ validParams<LeastSquaresFit>()
params.addRequiredParam<std::string>("x_name", "The name of the independent variable");
params.addRequiredParam<std::string>("y_name", "The name of the dependent variable");
params.addRequiredParam<unsigned int>("order", "The order of the polynomial fit");
params.addParam<bool>(
"truncate_order",
true,
"Truncate the order of the fitted polynomial if an insufficient number of data points are "
"provided. If this is set to false, an error will be generated in that case.");
params.addParam<unsigned int>("num_samples", "The number of samples to be output");
params.addParam<Real>(
"x_scale", 1.0, "Value used to scale x values (scaling is done after shifting)");
@@ -49,6 +54,7 @@ LeastSquaresFit::LeastSquaresFit(const InputParameters & parameters)
: GeneralVectorPostprocessor(parameters),
_vpp_name(getParam<VectorPostprocessorName>("vectorpostprocessor")),
_order(parameters.get<unsigned int>("order")),
_truncate_order(parameters.get<bool>("truncate_order")),
_x_name(getParam<std::string>("x_name")),
_y_name(getParam<std::string>("y_name")),
_x_values(getVectorPostprocessorValue("vectorpostprocessor", _x_name)),
@@ -126,7 +132,7 @@ LeastSquaresFit::execute()
y_values[i] = (y_values[i] + _y_shift) * _y_scale;
}

PolynomialFit pf(x_values, y_values, _order, true);
PolynomialFit pf(x_values, y_values, _order, _truncate_order);
pf.generate();

if (_output_type == "Samples")
@@ -26,6 +26,11 @@ validParams<LeastSquaresFitHistory>()
params.addRequiredParam<std::string>("x_name", "The name of the independent variable");
params.addRequiredParam<std::string>("y_name", "The name of the dependent variable");
params.addRequiredParam<unsigned int>("order", "The order of the polynomial fit");
params.addParam<bool>(
"truncate_order",
true,
"Truncate the order of the fitted polynomial if an insufficient number of data points are "
"provided. If this is set to false, an error will be generated in that case.");
params.addParam<Real>(
"x_scale", 1.0, "Value used to scale x values (scaling is done after shifting)");
params.addParam<Real>(
@@ -48,6 +53,7 @@ LeastSquaresFitHistory::LeastSquaresFitHistory(const InputParameters & parameter
: GeneralVectorPostprocessor(parameters),
_vpp_name(getParam<VectorPostprocessorName>("vectorpostprocessor")),
_order(parameters.get<unsigned int>("order")),
_truncate_order(parameters.get<bool>("truncate_order")),
_x_name(getParam<std::string>("x_name")),
_y_name(getParam<std::string>("y_name")),
_x_values(getVectorPostprocessorValue("vectorpostprocessor", _x_name)),
@@ -86,7 +92,7 @@ LeastSquaresFitHistory::execute()
y_values[i] = (y_values[i] + _y_shift) * _y_scale;
}

PolynomialFit pf(x_values, y_values, _order, true);
PolynomialFit pf(x_values, y_values, _order, _truncate_order);
pf.generate();

std::vector<Real> coeffs = pf.getCoefficients();
@@ -0,0 +1,2 @@
id,u
0.0,1.0
@@ -0,0 +1,3 @@
id,u
0.0,1.0
1.0,2.0
@@ -0,0 +1,4 @@
id,u
0.0,1.0
1.0,3.0
2.0,7.0
@@ -0,0 +1,2 @@
coefficients
1
@@ -0,0 +1,3 @@
coefficients
1
1
@@ -0,0 +1,4 @@
coefficients
1
1
1
@@ -0,0 +1,40 @@
[Problem]
solve = false
[]

[Mesh]
type = GeneratedMesh
dim = 1
nx = 1
[]

[Executioner]
type = Transient
start_time = 0.0
end_time = 0.0
[]

[VectorPostprocessors]
[./csv_data]
type = CSVReader
csv_file = fit_data_0.csv
header = true
outputs = none
[../]
[./least_squares_fit_coeffs]
type = LeastSquaresFit
vectorpostprocessor = csv_data
x_name = 'id'
y_name = 'u'
order = 0
output = coefficients
truncate_order = false
execute_on = initial
[../]
[]

[Outputs]
file_base = csv0
execute_on = initial
csv = true
[]
@@ -1,7 +1,49 @@
[Tests]
[./least_squares]
issues = '#7907 #4464'
requirement = 'The LeastSquaresFit vectorpostprocessor shall compute a least squares fit of a first-order polynomial sampled from a solution field using LineValueSampler with shifting and scaling parameters specified'
design = 'LeastSquaresFit.md LineValueSampler.md'
type = 'CSVDiff'
input = 'least_squares_fit.i'
csvdiff = 'out_least_squares_fit_coeffs_0001.csv out_least_squares_fit_sample_0001.csv out_shift_and_scale_y_least_squares_fit_sample_0001.csv out_shift_and_scale_x_least_squares_fit_coeffs_0001.csv out_shift_and_scale_x_least_squares_fit_sample_0001.csv out_shift_and_scale_y_least_squares_fit_coeffs_0001.csv'
[../]
[./least_squares_csv0]
issues = '#13498'
requirement = 'The LeastSquaresFit vectorpostprocessor shall compute a least squares fit of a zeroth-rder polynomial with data provided by a CSVReader'
design = 'LeastSquaresFit.md CSVReader.md'
type = 'CSVDiff'
input = 'least_squares_fit_csv_data.i'
csvdiff = 'csv0_least_squares_fit_coeffs_0000.csv'
recover = false
[../]
[./least_squares_csv1]
issues = '#13498'
requirement = 'The LeastSquaresFit vectorpostprocessor shall compute a least squares fit of a first-rder polynomial with data provided by a CSVReader'
design = 'LeastSquaresFit.md CSVReader.md'
type = 'CSVDiff'
input = 'least_squares_fit_csv_data.i'
cli_args = 'VectorPostprocessors/csv_data/csv_file=fit_data_1.csv VectorPostprocessors/least_squares_fit_coeffs/order=1 Outputs/file_base=csv1'
csvdiff = 'csv1_least_squares_fit_coeffs_0000.csv'
recover = false
[../]
[./least_squares_csv2]
issues = '#13498'
requirement = 'The LeastSquaresFit vectorpostprocessor shall compute a least squares fit of a second-rder polynomial with data provided by a CSVReader'
design = 'LeastSquaresFit.md CSVReader.md'
type = 'CSVDiff'
input = 'least_squares_fit_csv_data.i'
cli_args = 'VectorPostprocessors/csv_data/csv_file=fit_data_2.csv VectorPostprocessors/least_squares_fit_coeffs/order=2 Outputs/file_base=csv2'
csvdiff = 'csv2_least_squares_fit_coeffs_0000.csv'
recover = false
[../]
[./least_squares_csv3_order_err]
issues = '#13498'
requirement = 'The LeastSquaresFit vectorpostprocessor shall generate an error if a fit for a third-order polynomial is requested and only three data points are provided'
design = 'LeastSquaresFit.md CSVReader.md'
type = 'RunException'
expect_err = 'PolynomialFit requires an order less than the size of the input vector'
input = 'least_squares_fit_csv_data.i'
cli_args = 'VectorPostprocessors/csv_data/csv_file=fit_data_2.csv VectorPostprocessors/least_squares_fit_coeffs/order=3 Outputs/file_base=csv2_order_err'
recover = false
[../]
[]

0 comments on commit 7f1c270

Please sign in to comment.
You can’t perform that action at this time.