OpenRadioss 2025.1.11
OpenRadioss project
Loading...
Searching...
No Matches
cpp_table_mat_spline_fit.cpp
Go to the documentation of this file.
1#include <iostream>
2#include <fstream>
3#include <vector>
4#include <cmath>
5#include <iomanip>
6#include <limits>
7#include <algorithm>
8
9using namespace std;
10
11// --- Isotone regression by the Pool Adjacent Violators (PAV) algorithm
12void isotone_project_pav(std::vector<double> y,
13 std::vector<double> w_in,
14 std::vector<double>& z)
15{
16 const int n = (int)y.size();
17 z.assign(n, 0.0);
18 if (n==0) return;
19 if (n==1){ z[0]=y[0]; return; }
20
21 double ymin = y[0], ymax = y[0];
22 for (int i=1;i<n;++i){ ymin = std::min(ymin,y[i]); ymax = std::max(ymax,y[i]); }
23 const double range_y = std::max(1.0, ymax - ymin);
24 const double abs_tol = 1e-12 * range_y;
25 const double rel_tol = 1e-12;
26 const double eps_w = 1e-15;
27
28 struct Block{ int L, R; double sw, sy; };
29 std::vector<Block> S; S.reserve(n);
30
31 for (int i=0;i<n;++i){
32 double yi = y[i];
33 double wi = std::isfinite(w_in[i]) ? w_in[i] : 1.0;
34 if (!std::isfinite(yi)) {
35 yi = (i>0 ? z[i-1] : 0.0);
36 }
37 wi = std::max(wi, 0.0);
38 if (wi==0.0) wi = eps_w;
39
40 S.push_back({i,i,wi,wi*yi});
41
42 while (S.size()>=2){
43 auto &B2 = S.back();
44 auto &B1 = S[S.size()-2];
45 double m1 = B1.sy / B1.sw;
46 double m2 = B2.sy / B2.sw;
47
48 double eps_pav = abs_tol + rel_tol*std::max(std::abs(m1), std::abs(m2));
49 if (m1 <= m2 + eps_pav) break;
50
51 B1.sw += B2.sw;
52 B1.sy += B2.sy;
53 B1.R = B2.R;
54 S.pop_back();
55 }
56 z[i] = yi;
57 }
58
59 for (const auto& B : S){
60 double m = B.sy / B.sw;
61 for (int j=B.L; j<=B.R; ++j) z[j] = m;
62 }
63}
64
65// --- Isotone smoothing (one wheel mu). Fix y(0)=0 if one x equals 0.
66void smooth_isotone(const std::vector<double>& x,
67 const std::vector<double>& y_in,
68 std::vector<double>& z,
69 double mu = 1e-2,
70 int maxit = 500, double tol = 1e-9)
71{
72 const int n = (int)x.size();
73 std::vector<double> w(n,1.0);
74 z = y_in;
75
76 int i0 = -1; for (int i=0;i<n;++i) if (std::abs(x[i])<1e-15) { i0=i; break; }
77 if (i0>=0) z[i0]=0.0;
78
79 const double eta = 1.0 / (1.0 + 4.0*mu);
80 std::vector<double> g(n), zprev(n);
81
82 auto add_Lap1D = [&](const std::vector<double>& v, std::vector<double>& out){
83 out[0] += mu * ( v[0] - v[1] );
84 for (int i=1;i<n-1;++i) out[i] += mu * (2*v[i] - v[i-1] - v[i+1]);
85 out[n-1] += mu * ( v[n-1] - v[n-2] );
86 };
87
88 for (int it=0; it<maxit; ++it){
89 zprev = z;
90 g.assign(n, 0.0);
91 for (int i=0;i<n;++i) g[i] = (z[i]-y_in[i]);
92 add_Lap1D(z, g);
93
94 for (int i=0;i<n;++i) z[i] -= eta * g[i];
95
96 if (i0>=0) z[i0] = 0.0;
97
98 isotone_project_pav(z, w, z);
99
100 double diff=0.0;
101 for (int i=0;i<n;++i){ double d=z[i]-zprev[i]; diff+=d*d; }
102 if (diff < tol) break;
103 }
104}
105
106// --- PCHIP (Fritsch–Carlson) slopes
107void pchip_slopes(const std::vector<double>& x,
108 const std::vector<double>& z,
109 std::vector<double>& m)
110{
111 const int n = (int)x.size();
112 m.assign(n, 0.0);
113 if (n==1){ m[0]=0.0; return; }
114 std::vector<double> h(n-1), d(n-1);
115 for (int i=0;i<n-1;++i){
116 h[i] = x[i+1]-x[i];
117 d[i] = (z[i+1]-z[i])/h[i];
118 }
119 m[0] = d[0];
120 m[n-1] = d[n-2];
121 for (int i=1;i<n-1;++i){
122 if ( (d[i-1]*d[i]) <= 0.0 ) { m[i]=0.0; }
123 else {
124 double w1 = 2.0*h[i] + h[i-1];
125 double w2 = h[i] + 2.0*h[i-1];
126 m[i] = (w1 + w2) / ( (w1/d[i-1]) + (w2/d[i]) );
127 }
128 }
129}
130
131// --- PCHIP evaluation
132double pchip_eval(const std::vector<double>& x,
133 const std::vector<double>& z,
134 const std::vector<double>& m,
135 double xi)
136{
137 const int n = (int)x.size();
138 if (xi <= x.front()) return z.front();
139 if (xi >= x.back()) return z.back();
140 int k = (int)(std::upper_bound(x.begin(), x.end(), xi) - x.begin()) - 1; // k in [0..n-2]
141 double h = x[k+1]-x[k];
142 double t = (xi - x[k]) / h;
143 double t2 = t*t, t3 = t2*t;
144
145 double h00 = ( 2*t3 - 3*t2 + 1);
146 double h10 = ( t3 - 2*t2 + t)*h;
147 double h01 = (-2*t3 + 3*t2 );
148 double h11 = ( t3 - t2 )*h;
149
150 return h00*z[k] + h10*m[k] + h01*z[k+1] + h11*m[k+1];
151}
152
153
154//----------------------------------------------------------------------------------------------------------------
155// C Interface to Fortran
156// ---------------------------------------------------------------------------------------------------------------
157extern "C" {
158 void cpp_table_mat_spline_fit(int s_inp, double* x_inp,double* y_inp,int nout, double* x_out,
159 double* y_out, double lambda) {
160
161 std::vector<double> x_raw(s_inp), y_raw(s_inp);
162 for (int i=0;i<s_inp;++i){ x_raw[i]=x_inp[i]; y_raw[i]=y_inp[i]; }
163
164 const int n = (int)x_raw.size();
165 if (n==0){
166 x_out[0]=0.0; y_out[0]=0.0; return;
167 }
168 if (n==1){
169 for (int i=0;i<nout;++i){ x_out[i]=x_raw[0]; y_out[i]=y_raw[0]; }
170 return;
171 }
172
173 std::vector<double> z;
174 smooth_isotone(x_raw, y_raw, z, /*mu=*/std::max(0.0,lambda));
175
176 std::vector<double> m;
177 pchip_slopes(x_raw, z, m);
178
179 double xmin = x_raw.front(), xmax = x_raw.back();
180 if (nout<2) nout=2;
181
182 for (int i=0;i<nout;++i){
183 double xi = xmin + (xmax - xmin) * (double)i / (double)(nout-1);
184 x_out[i] = xi;
185 y_out[i] = pchip_eval(x_raw, z, m, xi);
186 }
187
188 }
189}
void pchip_slopes(const std::vector< double > &x, const std::vector< double > &z, std::vector< double > &m)
double pchip_eval(const std::vector< double > &x, const std::vector< double > &z, const std::vector< double > &m, double xi)
void cpp_table_mat_spline_fit(int s_inp, double *x_inp, double *y_inp, int nout, double *x_out, double *y_out, double lambda)
void isotone_project_pav(std::vector< double > y, std::vector< double > w_in, std::vector< double > &z)
void smooth_isotone(const std::vector< double > &x, const std::vector< double > &y_in, std::vector< double > &z, double mu=1e-2, int maxit=500, double tol=1e-9)
subroutine ymax(idn, fac, npc, pld, stiffmin, stiffmax, stiffini, stiffavg)
Definition law100_upd.F:274
n