Skip to content

Commit

Permalink
Resolve issues with polynomial order truncation in LeastSquaresFit cl…
Browse files Browse the repository at this point in the history
…oses idaholab#13498

Add a 'truncate_order' option to LeastSquaresFit and LeastSquaresFitHistory

Correct logic for determining required points for a given polynomial
order in PolynomialFit.C

Add tests for fits of polynomials with order 0, 1, and 2

Add test for insufficient order error
  • Loading branch information
bwspenc committed Jun 3, 2019
1 parent c3c0499 commit 489b827
Show file tree
Hide file tree
Showing 15 changed files with 144 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 13 additions & 7 deletions framework/include/vectorpostprocessors/LeastSquaresFit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/**
Expand All @@ -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;
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
23 changes: 10 additions & 13 deletions framework/src/utils/PolynomialFit.C
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@

#include "PolynomialFit.h"

#include "MooseError.h"

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

int PolynomialFit::_file_number = 0;

Expand All @@ -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;
}
Expand Down
8 changes: 7 additions & 1 deletion framework/src/vectorpostprocessors/LeastSquaresFit.C
Original file line number Diff line number Diff line change
Expand Up @@ -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)");
Expand All @@ -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)),
Expand Down Expand Up @@ -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")
Expand Down
8 changes: 7 additions & 1 deletion framework/src/vectorpostprocessors/LeastSquaresFitHistory.C
Original file line number Diff line number Diff line change
Expand Up @@ -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>(
Expand All @@ -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)),
Expand Down Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
id,u
0.0,1.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
id,u
0.0,1.0
1.0,2.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
id,u
0.0,1.0
1.0,3.0
2.0,7.0
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
coefficients
1
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
coefficients
1
1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
coefficients
1
1
1
Original file line number Diff line number Diff line change
@@ -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
[]
38 changes: 38 additions & 0 deletions test/tests/vectorpostprocessors/least_squares_fit/tests
Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
[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'
[../]
[./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'
[../]
[./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'
[../]
[./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'
[../]
[]

0 comments on commit 489b827

Please sign in to comment.