CoolProp 8.0.0
An open-source fluid property and humid air property database
SVDDecomposition.h
Go to the documentation of this file.
1#ifndef COOLPROP_SVD_SVD_DECOMPOSITION_H
2#define COOLPROP_SVD_SVD_DECOMPOSITION_H
3
4#include <cstdint>
5#include <vector>
6
7namespace CoolProp {
8namespace svd {
9
10// Output transform applied to the SVD result. We store the SVD of a
11// matrix in some transformed space (typically log of a strictly positive
12// property), and undo the transform at evaluation time.
13enum class OutputTransform : std::uint8_t
14{
15 IDENTITY, // value = sum_k S_k u_k v_k (no wrap)
16 EXP // value = exp(sum_k S_k u_k v_k) (matrix was log of property)
17};
18
19// Slope source used to build the per-mode 1D slopes (dU_dx, dV_S_dy).
20// Affects build only — the eval kernel reads slopes from arrays and is
21// agnostic to how they were computed.
22enum class SlopeSource : std::uint8_t
23{
24 NATURAL_CUBIC_SPLINE, // default; C^2 continuous interpolant of each mode
25 HERMITE_FD, // central finite difference (svd_bench.cpp parity)
26 PCHIP // monotone cubic; useful when monotonicity matters
27};
28
29// Plain-old-data container ferrying a 2D rank-r SVD from the offline
30// builder to the runtime evaluator.
31//
32// Layout choices deliberately diverge from `dev/svd_bench.cpp` for
33// performance:
34// - V is stored transposed relative to svd_bench.cpp's Vt: here
35// `V_S[j*rank + k]` is the k-th mode at y-index j, so the per-mode
36// scan in eval is unit-stride.
37// - The singular values S are *folded into* V_S — V_S[j,k] = V[j,k] * S[k].
38// The eval kernel becomes a plain dot product. Storage saving:
39// rank doubles (negligible). CPU saving: one multiply per mode per
40// call (small but free).
41// - dU_dx and dV_S_dy carry the precomputed slopes used by the cubic
42// Hermite kernel; one slope per (axis grid point, mode).
43//
44// This struct is NOT trivially copyable — the std::vector members own
45// heap storage, so a memcpy of the SVDDecomposition object itself
46// produces garbage. Callers wanting GPU portability should `cudaMemcpy`
47// the underlying contiguous buffers (U.data(), V_S.data(), dU_dx.data(),
48// dV_S_dy.data(), x_grid.data(), y_grid.data()) into device buffers
49// individually and read them with an Eigen::Map on the device side.
50// Device-side evaluation will agree with host evaluation within a few
51// ulp — not byte-exact — because nvcc fuses multiply-and-accumulate by
52// default (`--fmad=true`) and the slopes themselves were computed on
53// the host with whatever rounding the spline solver chose.
55{
56 std::int32_t NX = 0; // number of grid points on x axis
57 std::int32_t NY = 0; // number of grid points on y axis
58 std::int32_t rank = 0; // truncation rank r (rank <= min(NX, NY))
59
61 // Provenance only — the eval kernel reads slopes from dU_dx /
62 // dV_S_dy and is agnostic to which strategy filled them. Kept on
63 // the struct so a deserialised decomposition is self-describing.
65
66 std::vector<double> x_grid; // size NX
67 std::vector<double> y_grid; // size NY
68
69 // U: NX rows, rank columns, row-major. U[i*rank + k] is mode k at x_i.
70 std::vector<double> U;
71 // dU/dx slopes co-located with U.
72 std::vector<double> dU_dx;
73
74 // V with S folded in: NY rows, rank columns, row-major.
75 // V_S[j*rank + k] is sigma_k * V[j, k].
76 std::vector<double> V_S;
77 // dV_S/dy slopes co-located with V_S.
78 std::vector<double> dV_S_dy;
79
80 // Raw singular values kept for diagnostics / debug output. Not used
81 // by the hot path; the values are already folded into V_S.
82 std::vector<double> S;
83};
84
85} // namespace svd
86} // namespace CoolProp
87
88#endif // COOLPROP_SVD_SVD_DECOMPOSITION_H