OpenRadioss 2025.1.11
OpenRadioss project
Loading...
Searching...
No Matches
cpp_python_sampling.h
Go to the documentation of this file.
1//Copyright> OpenRadioss
2//Copyright> Copyright (C) 1986-2025 Altair Engineering Inc.
3//Copyright>
4//Copyright> This program is free software: you can redistribute it and/or modify
5//Copyright> it under the terms of the GNU Affero General Public License as published by
6//Copyright> the Free Software Foundation, either version 3 of the License, or
7//Copyright> (at your option) any later version.
8//Copyright>
9//Copyright> This program is distributed in the hope that it will be useful,
10//Copyright> but WITHOUT ANY WARRANTY; without even the implied warranty of
11//Copyright> MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12//Copyright> GNU Affero General Public License for more details.
13//Copyright>
14//Copyright> You should have received a copy of the GNU Affero General Public License
15//Copyright> along with this program. If not, see <https://www.gnu.org/licenses/>.
16//Copyright>
17//Copyright>
18//Copyright> Commercial Alternative: Altair Radioss Software
19//Copyright>
20//Copyright> As an alternative to this open-source version, Altair also offers Altair Radioss
21//Copyright> software under a commercial license. Contact Altair to discuss further if the
22//Copyright> commercial version may interest you: https://www.altair.com/radioss/.
23#include <iostream>
24#include <vector>
25#include <cmath> // For isnan, isinf, fabs, exp
26#include <algorithm> // For std::sort
27#include <limits>
28#include <iomanip> // For setprecision
29#include <set>
30#include <utility> // For std::pair
31#include <numeric>
32
33// Function to generate a linearly spaced vector
34std::vector<double> linear_spacing(double start, double end, size_t n, bool include_start) {
35 std::vector<double> points(n);
36
37 for (size_t i = 0; i < n; ++i) {
38 double factor = include_start ? i : (i + 1);
39 points[i] = start + factor * (end - start) / (n - 1);
40 }
41 return points;
42}
43
44// Generate sampling with 5N points and avoid duplicate boundary values
45std::vector<double> initial_sampling(double x_max, size_t n) {
46 // Define the ranges
47 n = n / 5;
48 std::vector<double> range_starts = {0, 1, 10, 100, 1000};
49 std::vector<double> range_ends = {1, 10, 100, 1000, 10000};
50
51 std::vector<double> X;
52 X.reserve(5 * n); // Reserve space for efficiency
53 // Generate points for each range
54 for (size_t i = 0; i < range_starts.size(); ++i) {
55 bool include_start = (i == 0); // Only include start for the first range
56 std::vector<double> range_points = linear_spacing(
57 range_starts[i], range_ends[i], n, include_start
58 );
59 X.insert(X.end(), range_points.begin(), range_points.end());
60 }
61 // scale the points to 0 xmax
62 double x_min_right = 0;
63// for (size_t i = 0; i < X.size(); i++) {
64// X[i] = x_min_right + X[i] * (x_max - x_min_right) / 10000;
65// }
66 X[0] = (X[0] + X[1]) / 2.0;
67 return X;
68}
69
70
71
72
73double safe_cast_to_double(long double d) {
74 // Handle NaN cases
75 if (std::isnan(d)) {
76 return 0.0;
77 }
78
79 // Clamp to the maximum representable double if too large
80 if (d > std::numeric_limits<double>::max()) {
81 return std::numeric_limits<double>::max();
82 }
83
84 // Clamp to the minimum representable double (negative) if too small
85 if (d < -std::numeric_limits<double>::max()) {
86 return -std::numeric_limits<double>::max();
87 }
88
89 // Otherwise, cast safely
90 return static_cast<double>(d);
91}
92
93// remove non-finite values
94void clean_values(std::vector<double>& X, std::vector<double>& Y) {
95 // initial size
96 size_t N = X.size();
97 // Remove non-finite values
98 std::vector<double> XX;
99 std::vector<double> YY;
100 for (size_t i = 0; i < X.size(); i++)
101 {
102 if (std::isfinite(Y[i]))
103 {
104 if(i > 0)
105 {
106 if (fabs(Y[i] - Y[i-1]) > 1e-10)
107 {
108 XX.push_back(X[i]);
109 YY.push_back(Y[i]);
110 }
111 } else {
112 XX.push_back(X[i]);
113 YY.push_back(Y[i]);
114 }
115 }
116 }
117 if(XX.size() == 0) {
118 return;
119 }
120 X = XX;
121 Y = YY;
122 const size_t new_size = X.size();
123 double Xlast = X[new_size - 1];
124 double Ylast = Y[new_size - 1];
125 for(size_t i = new_size ; i < N; i++){
126 X.push_back(Xlast + 1.0);
127 Y.push_back(Ylast);
128 }
129}
130
131// Function to compute curvature robustly
132long double compute_curvature(const double & F_im1, const double & F_i, const double &F_ip1,const double & h1, const double & h2) {
133 // Cast inputs to long double for higher precision
134 long double F_im1_ld = static_cast<long double>(F_im1);
135 long double F_i_ld = static_cast<long double>(F_i);
136 long double F_ip1_ld = static_cast<long double>(F_ip1);
137 long double h1_ld = static_cast<long double>(h1);
138 long double h2_ld = static_cast<long double>(h2);
139
140 // First derivative using non-uniform spacing
141 long double F_prime = (h2_ld * (F_i_ld - F_im1_ld) + h1_ld * (F_ip1_ld - F_i_ld)) / (h1_ld * h2_ld);
142
143 // Second derivative using non-uniform spacing
144 long double F_double_prime = 2 * ((F_ip1_ld - F_i_ld) / h2_ld - (F_i_ld - F_im1_ld) / h1_ld) / (h1_ld + h2_ld);
145
146 // Curvature formula
147 long double denom = std::pow(1 + F_prime * F_prime, 1.5L);
148 if (denom == 0.0L) return 0.0; // Avoid division by zero
149 long double curvature = std::abs(F_double_prime) / denom;
150 // Cast the result back to double
151 // if NaN or Inf return 0.0
152 if (std::isnan(curvature) || std::isinf(curvature)) {
153 return 0.0L;
154 }
155 return curvature;
156}
157
158// Select n_points based on curvature
159std::vector<double> select_points(const std::vector<double>& x, const std::vector<double>& F_values, size_t n_points) {
160 size_t n = x.size();
161 if (n_points >= n) {
162 n_points = n;
163 return x;
164 }
165
166 // Step 1: Compute curvature for all points
167 std::vector<long double> curvature(n, 0.0);
168 for (size_t i = 1; i < n - 1; ++i) {
169 double h1 = x[i] - x[i - 1];
170 double h2 = x[i + 1] - x[i];
171 if (h1 == 0.0 || h2 == 0.0) {
172 curvature[i] = 0.0;
173 continue;
174 }
175 //if F_values[i] is not finite, curvature is 0
176 if (!std::isfinite(F_values[i]) || !std::isfinite(F_values[i - 1]) || !std::isfinite(F_values[i + 1])) {
177 curvature[i] = 0.0;
178 continue;
179 }
180 curvature[i] = compute_curvature(F_values[i - 1], F_values[i], F_values[i + 1], h1, h2);
181 }
182
183 // Step 2: Normalize curvature to create a density function
184 long double curvature_sum = std::accumulate(curvature.begin(), curvature.end(), 0.0);
185 std::vector<long double> density(n, 0.0L);
186
187 density[0] = sqrt(curvature[0] * (2*(x[1] - x[0]))); // Use sqrt(curvature)
188 density[n-1] = sqrt(curvature[n-1] * (2*(x[n-1] - x[n-2]))); // Use sqrt(curvature)
189 for (size_t i = 0; i < n-1; ++i) {
190 density[i] = std::sqrt(curvature[i] * (x[i+1] - x[i])); // Use sqrt(curvature)
191 }
192 // get the maximum density
193 long double max_density = *std::max_element(density.begin(), density.end());
194 // density = density + 0.001*max_density
195 for (size_t i = 0; i < n; ++i) {
196 density[i] += 0.001L * max_density;
197 }
198 long double density_sum = std::accumulate(density.begin(), density.end(), 0.0);
199 for (auto& d : density) {
200 d /= density_sum; // Normalize
201 }
202
203 // Step 3: Compute cumulative density function (CDF)
204 std::vector<long double> cdf(n, 0.0L);
205 std::partial_sum(density.begin(), density.end(), cdf.begin());
206
207 // Step 4: Select n_points based on the CDF
208 std::vector<double> selected_points;
209 selected_points.reserve(n_points);
210 double step = 1.0 / (n_points - 1);
211 double target = 0.0;
212
213 for (size_t i = 0; i < n_points; ++i) {
214 auto it = std::lower_bound(cdf.begin(), cdf.end(), target);
215 size_t idx = std::distance(cdf.begin(), it);
216 selected_points.push_back(x[std::min(idx, n - 1)]); // Ensure idx is within bounds
217 target += step;
218 }
219
220 // Ensure boundary points are included
221 if (std::find(selected_points.begin(), selected_points.end(), x.front()) == selected_points.end()) {
222 selected_points[0] = x.front();
223 }
224 if (std::find(selected_points.begin(), selected_points.end(), x.back()) == selected_points.end()) {
225 selected_points[n_points - 1] = x.back();
226 }
227
228 return selected_points;
229}
long double compute_curvature(const double &F_im1, const double &F_i, const double &F_ip1, const double &h1, const double &h2)
std::vector< double > initial_sampling(double x_max, size_t n)
double safe_cast_to_double(long double d)
std::vector< double > linear_spacing(double start, double end, size_t n, bool include_start)
void clean_values(std::vector< double > &X, std::vector< double > &Y)
std::vector< double > select_points(const std::vector< double > &x, const std::vector< double > &F_values, size_t n_points)
end[inform, rinform, sol, inst, schur, redrhs, pivnul_list, sym_perm, uns_perm, icntl, cntl, colsca_out, rowsca_out, keep_out, dkeep_out]
Definition dmumps.m:40
#define N
n