Documentation 6b54b78464
Loading...
Searching...
No Matches
common.hpp
Go to the documentation of this file.
1/*!
2 * \file common.hpp
3 * \brief Common convection-related methods.
4 * \author P. Gomes, F. Palacios, T. Economon
5 * \version 8.5.0 "Harrier"
6 *
7 * SU2 Project Website: https://su2code.github.io
8 *
9 * The SU2 Project is maintained by the SU2 Foundation
10 * (http://su2foundation.org)
11 *
12 * Copyright 2012-2026, SU2 Contributors (cf. AUTHORS.md)
13 *
14 * SU2 is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
18 *
19 * SU2 is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
23 *
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with SU2. If not, see <http://www.gnu.org/licenses/>.
26 */
27
28#pragma once
29
30#include "../../CNumericsSIMD.hpp"
31#include "../../util.hpp"
32#include "../variables.hpp"
33#include "../../../variables/CNSVariable.hpp"
34
35/*!
36 * \brief Retrieve primitive variables for points i/j, reconstructing them if needed.
37 * \note Density and enthalpy are recomputed from ideal gas EOS.
38 * \param[in] iEdge, iPoint, jPoint - Edge and its nodes.
39 * \param[in] gamma - Heat capacity ratio.
40 * \param[in] gasConst - Specific gas constant.
41 * \param[in] muscl - If true, reconstruct, else simply fetch.
42 * \param[in] kappa - Blending coefficient for MUSCL reconstruction.
43 * \param[in] umusclRamp - MUSCL 1st-2nd order ramp times Newton-Krylov relaxation.
44 * \param[in] limiterType - Type of flux limiter.
45 * \param[in] V1st - Pair of compressible flow primitives for nodes i,j.
46 * \param[in] vector_ij - Distance vector from i to j.
47 * \param[in] solution - Entire solution container (a derived CVariable).
48 * \param[out] nonPhysical - Signals that the edge is treated as non-physical.
49 * \return Pair of primitive variables.
50 */
51template<class ReconVarType, class PrimVarType, size_t nDim, class VariableType>
53 const Int& iPoint, const Int& jPoint,
54 const su2double& gamma,
55 const su2double& gasConst,
56 const bool muscl,
57 const su2double& kappa,
58 const su2double& umusclRamp,
59 const LIMITER limiterType,
60 const CPair<PrimVarType>& V1st,
61 const VectorDbl<nDim>& vector_ij,
62 const VariableType& solution,
63 Double& nonPhysical) {
64 static_assert(ReconVarType::nVar <= PrimVarType::nVar);
65
66 const auto& gradients = solution.GetGradient_Reconstruction();
67 const auto& limiters = solution.GetLimiter_Primitive();
68
70
71 for (size_t iVar = 0; iVar < ReconVarType::nVar; ++iVar) {
72 V.i.all(iVar) = V1st.i.all(iVar);
73 V.j.all(iVar) = V1st.j.all(iVar);
74 }
75
76 if (muscl) {
77 /*--- Reconstruct density and enthalpy without using their gradients. ---*/
78 constexpr auto nVarGrad = ReconVarType::nVar - 2;
79 reconstruct<nVarGrad>(iPoint, jPoint, vector_ij, gradients, limiters, limiterType, 0, V, kappa, umusclRamp);
80 /*--- Recompute density using the reconstructed pressure and temperature. ---*/
81 V.i.density() = V.i.pressure() / (gasConst * V.i.temperature());
82 V.j.density() = V.j.pressure() / (gasConst * V.j.temperature());
83
84 /*--- Reconstruct enthalpy using dH/dT = Cp and dH/dv = v. Recomputing enthalpy would cause
85 * stability issues because we use rho E = rho H - P, which loses its relation to temperature
86 * if both rho and H are recomputed. This only seems to be an issue for wall-function meshes.
87 * NOTE: This "one-sided" reconstruction does not lose much of the U-MUSCL benefit, because
88 * the static enthalpy is linear, and for the KE term we do the equivalent of using the
89 * average dH/dv, which is exact for quadratic functions. ---*/
90 const su2double cp = gasConst * gamma / (gamma - 1);
91 V.i.enthalpy() += cp * (V.i.temperature() - V1st.i.temperature());
92 V.j.enthalpy() += cp * (V.j.temperature() - V1st.j.temperature());
93 for (size_t iDim = 0; iDim < nDim; ++iDim) {
94 V.i.enthalpy() += 0.5 * (pow(V.i.velocity(iDim), 2) - pow(V1st.i.velocity(iDim), 2));
95 V.j.enthalpy() += 0.5 * (pow(V.j.velocity(iDim), 2) - pow(V1st.j.velocity(iDim), 2));
96 }
97
98 /*--- Detect a non-physical reconstruction based on negative pressure or density. ---*/
99 const Double neg_p_or_rho = fmax(fmin(V.i.pressure(), V.j.pressure()) < 0.0,
100 fmin(V.i.density(), V.j.density()) < 0.0);
101 /*--- Test the sign of the Roe-averaged speed of sound. ---*/
102 const Double R = sqrt(abs(V.j.density() / V.i.density()));
103 /*--- Delay dividing by R+1 until comparing enthalpy and velocity magnitude. ---*/
104 const Double enthalpy = R*V.j.enthalpy() + V.i.enthalpy();
105 Double v_squared = 0.0;
106 for (size_t iDim = 0; iDim < nDim; ++iDim) {
107 v_squared += pow(R*V.j.velocity(iDim) + V.i.velocity(iDim), 2);
108 }
109 /*--- Multiply enthalpy by R+1 since v^2 was not divided by (R+1)^2.
110 * Note: a = sqrt((gamma-1) * (H - 0.5 * v^2)) ---*/
111 const Double neg_sound_speed = enthalpy * (R+1) < 0.5 * v_squared;
112
113 /*--- Revert to first order if the state is non-physical. ---*/
114 nonPhysical = fmax(neg_p_or_rho, neg_sound_speed);
115 /*--- Handle SIMD dimensions 1 by 1. ---*/
116 for (size_t k = 0; k < Double::Size; ++k) {
117 nonPhysical[k] = solution.UpdateNonPhysicalEdgeCounter(iEdge[k], nonPhysical[k]);
118 nonPhysical[k] = fmax(nonPhysical[k],
119 fmax(solution.OutlierMitigation(iPoint[k]),
120 solution.OutlierMitigation(jPoint[k])) / VariableType::MAX_OUTLIER_MITIGATION);
121 }
122 for (size_t iVar = 0; iVar < ReconVarType::nVar; ++iVar) {
123 V.i.all(iVar) = nonPhysical * V1st.i.all(iVar) + (1-nonPhysical) * V.i.all(iVar);
124 V.j.all(iVar) = nonPhysical * V1st.j.all(iVar) + (1-nonPhysical) * V.j.all(iVar);
125 }
126 } else {
127 nonPhysical = 0;
128 }
129 return V;
130}
131
132/*!
133 * \brief Compute and return the P tensor (compressible flow, ideal gas).
134 */
135template<size_t nDim, class RandomAccessIterator>
136FORCEINLINE MatrixDbl<nDim+2> pMatrix(const Double& gamma, const Double& density, const RandomAccessIterator& velocity,
137 const Double& projVel, const Double& speedSound, const VectorDbl<nDim>& normal) {
139 const Double vel2 = 0.5*squaredNorm<nDim>(velocity);
140
141 if (nDim == 2) {
142 pMat(0,0) = 1.0;
143 pMat(0,1) = 0.0;
144
145 pMat(1,0) = velocity[0];
146 pMat(1,1) = density*normal(1);
147
148 pMat(2,0) = velocity[1];
149 pMat(2,1) = -density*normal(0);
150
151 pMat(3,0) = vel2;
152 pMat(3,1) = density*(velocity[0]*normal(1) - velocity[1]*normal(0));
153 }
154 else {
155 pMat(0,0) = normal(0);
156 pMat(0,1) = normal(1);
157 pMat(0,2) = normal(2);
158
159 pMat(1,0) = velocity[0]*normal(0);
160 pMat(1,1) = velocity[0]*normal(1) - density*normal(2);
161 pMat(1,2) = velocity[0]*normal(2) + density*normal(1);
162
163 pMat(2,0) = velocity[1]*normal(0) + density*normal(2);
164 pMat(2,1) = velocity[1]*normal(1);
165 pMat(2,2) = velocity[1]*normal(2) - density*normal(0);
166
167 pMat(3,0) = velocity[2]*normal(0) - density*normal(1);
168 pMat(3,1) = velocity[2]*normal(1) + density*normal(0);
169 pMat(3,2) = velocity[2]*normal(2);
170
171 pMat(4,0) = vel2*normal(0) + density*(velocity[1]*normal(2) - velocity[2]*normal(1));
172 pMat(4,1) = vel2*normal(1) - density*(velocity[0]*normal(2) - velocity[2]*normal(0));
173 pMat(4,2) = vel2*normal(2) + density*(velocity[0]*normal(1) - velocity[1]*normal(0));
174 }
175
176 /*--- Last two columns. ---*/
177
178 const Double rhoOn2 = 0.5*density;
179 const Double rhoOnTwoC = rhoOn2 / speedSound;
180 pMat(0,nDim) = rhoOnTwoC;
181 pMat(0,nDim+1) = rhoOnTwoC;
182
183 for (size_t iDim = 0; iDim < nDim; ++iDim) {
184 pMat(iDim+1,nDim) = rhoOnTwoC * velocity[iDim] + rhoOn2 * normal(iDim);
185 pMat(iDim+1,nDim+1) = rhoOnTwoC * velocity[iDim] - rhoOn2 * normal(iDim);
186 }
187
188 pMat(nDim+1,nDim) = rhoOnTwoC * vel2 + rhoOn2 * (projVel + speedSound/(gamma-1));
189 pMat(nDim+1,nDim+1) = rhoOnTwoC * vel2 - rhoOn2 * (projVel - speedSound/(gamma-1));
190
191 return pMat;
192}
193
194/*!
195 * \brief Compute and return the inverse P tensor (compressible flow, ideal gas).
196 */
197template<size_t nDim, class RandomAccessIterator>
199 const RandomAccessIterator& velocity, const Double& projVel,
200 const Double& speedSound, const VectorDbl<nDim>& normal) {
201 MatrixDbl<nDim+2> pMatInv;
202
203 const Double c2 = pow(speedSound,2);
204 const Double vel2 = 0.5*squaredNorm<nDim>(velocity);
205 const Double oneOnRho = 1 / density;
206
207 if (nDim == 2) {
208 Double tmp = (gamma-1)/c2;
209 pMatInv(0,0) = 1.0 - tmp*vel2;
210 pMatInv(0,1) = tmp*velocity[0];
211 pMatInv(0,2) = tmp*velocity[1];
212 pMatInv(0,3) = -tmp;
213
214 pMatInv(1,0) = (normal(0)*velocity[1]-normal(1)*velocity[0])*oneOnRho;
215 pMatInv(1,1) = normal(1)*oneOnRho;
216 pMatInv(1,2) = -normal(0)*oneOnRho;
217 pMatInv(1,3) = 0.0;
218 }
219 else {
220 Double tmp = (gamma-1)/c2 * normal(0);
221 pMatInv(0,0) = normal(0) - tmp*vel2 - (normal(2)*velocity[1]-normal(1)*velocity[2])*oneOnRho;
222 pMatInv(0,1) = tmp*velocity[0];
223 pMatInv(0,2) = tmp*velocity[1] + normal(2)*oneOnRho;
224 pMatInv(0,3) = tmp*velocity[2] - normal(1)*oneOnRho;
225 pMatInv(0,4) = -tmp;
226
227 tmp = (gamma-1)/c2 * normal(1);
228 pMatInv(1,0) = normal(1) - tmp*vel2 + (normal(2)*velocity[0]-normal(0)*velocity[2])*oneOnRho;
229 pMatInv(1,1) = tmp*velocity[0] - normal(2)*oneOnRho;
230 pMatInv(1,2) = tmp*velocity[1];
231 pMatInv(1,3) = tmp*velocity[2] + normal(0)*oneOnRho;
232 pMatInv(1,4) = -tmp;
233
234 tmp = (gamma-1)/c2 * normal(2);
235 pMatInv(2,0) = normal(2) - tmp*vel2 - (normal(1)*velocity[0]-normal(0)*velocity[1])*oneOnRho;
236 pMatInv(2,1) = tmp*velocity[0] + normal(1)*oneOnRho;
237 pMatInv(2,2) = tmp*velocity[1] - normal(0)*oneOnRho;
238 pMatInv(2,3) = tmp*velocity[2];
239 pMatInv(2,4) = -tmp;
240 }
241
242 /*--- Last two rows. ---*/
243
244 const Double gamma_minus_1_on_rho_times_c = (gamma-1) / (density*speedSound);
245
246 for (size_t iVar = nDim; iVar < nDim+2; ++iVar) {
247 Double sign = (iVar==nDim)? 1 : -1;
248 pMatInv(iVar,0) = -sign*projVel*oneOnRho + gamma_minus_1_on_rho_times_c * vel2;
249 for (size_t iDim = 0; iDim < nDim; ++iDim) {
250 pMatInv(iVar,iDim+1) = sign*normal(iDim)*oneOnRho - gamma_minus_1_on_rho_times_c * velocity[iDim];
251 }
252 pMatInv(iVar,nDim+1) = gamma_minus_1_on_rho_times_c;
253 }
254
255 return pMatInv;
256}
257
258/*!
259 * \brief Convective projected (onto normal) flux (compressible flow).
260 */
261template<class PrimVarType, class ConsVarType, size_t nDim>
263 const ConsVarType& U,
264 const VectorDbl<nDim>& normal) {
265 static_assert(ConsVarType::nVar == nDim+2);
266 Double mdot = dot(U.momentum(), normal);
268 flux(0) = mdot;
269 for (size_t iDim = 0; iDim < nDim; ++iDim) {
270 flux(iDim+1) = mdot*V.velocity(iDim) + normal(iDim)*V.pressure();
271 }
272 flux(nDim+1) = mdot*V.enthalpy();
273 return flux;
274}
275
276/*!
277 * \brief Jacobian of the convective flux (compressible flow, ideal gas).
278 */
279template<size_t nDim, class RandomAccessIterator>
280FORCEINLINE MatrixDbl<nDim+2> inviscidProjJac(const Double& gamma, RandomAccessIterator velocity,
281 const Double& energy, const VectorDbl<nDim>& normal,
282 const Double& scale) {
284
285 Double projVel = dot(velocity, normal);
286 Double gamma_m_1 = gamma-1;
287 Double phi = 0.5*gamma_m_1*squaredNorm<nDim>(velocity);
288 Double a1 = gamma*energy - phi;
289
290 jac(0,0) = 0.0;
291 for (size_t iDim = 0; iDim < nDim; ++iDim) {
292 jac(0,iDim+1) = scale * normal(iDim);
293 }
294 jac(0,nDim+1) = 0.0;
295
296 for (size_t iDim = 0; iDim < nDim; ++iDim) {
297 jac(iDim+1,0) = scale * (normal(iDim)*phi - velocity[iDim]*projVel);
298 for (size_t jDim = 0; jDim < nDim; ++jDim) {
299 jac(iDim+1,jDim+1) = scale * (normal(jDim)*velocity[iDim] - gamma_m_1*normal(iDim)*velocity[jDim]);
300 }
301 jac(iDim+1,iDim+1) += scale * projVel;
302 jac(iDim+1,nDim+1) = scale * gamma_m_1 * normal(iDim);
303 }
304
305 jac(nDim+1,0) = scale * projVel * (phi-a1);
306 for (size_t iDim = 0; iDim < nDim; ++iDim) {
307 jac(nDim+1,iDim+1) = scale * (normal(iDim)*a1 - gamma_m_1*velocity[iDim]*projVel);
308 }
309 jac(nDim+1,nDim+1) = scale * gamma * projVel;
310
311 return jac;
312}
313
314/*!
315 * \brief (Low) Dissipation coefficient for Roe schemes.
316 */
317template<class VariableType>
319 const Int& jPoint,
320 const ENUM_ROELOWDISS type,
321 const VariableType& solution) {
322 if (type == NO_ROELOWDISS) {
323 return 1.0;
324 }
325
326 const auto& sol = static_cast<const CNSVariable&>(solution);
327 const auto& sensor = sol.GetSensor();
328 const auto& dissip = sol.GetRoe_Dissipation();
329
330 const Double si = gatherVariables(iPoint, sensor);
331 const Double sj = gatherVariables(jPoint, sensor);
332 const Double avgSensor = 0.5 * (si + sj);
333
334 const Double di = gatherVariables(iPoint, dissip);
335 const Double dj = gatherVariables(jPoint, dissip);
336 const Double avgDissip = 0.5 * (di + dj);
337
338 /*--- A minimum level of upwinding is used to enhance stability. ---*/
339 constexpr passivedouble minDissip = 0.05;
340
341 switch (type) {
342 case FD:
343 case FD_DUCROS: {
344 Double d = fmax(minDissip, 1.0 - avgDissip);
345
346 if (type == FD_DUCROS) {
347 /*--- See Jonhsen et al. JCP 229 (2010) pag. 1234 ---*/
348 d = fmax(d, 0.05 + 0.95*(avgSensor > 0.65));
349 }
350 return d;
351 }
352 case NTS:
353 return fmax(minDissip, avgDissip);
354
355 case NTS_DUCROS:
356 /*--- See Xiao et al. INT J HEAT FLUID FL 51 (2015) pag. 141
357 * https://doi.org/10.1016/j.ijheatfluidflow.2014.10.007 ---*/
358 return fmax(minDissip, avgSensor+avgDissip - avgSensor*avgDissip);
359
360 default:
361 assert(false);
362 return 1.0;
363 }
364}
365
366/*!
367 * \brief Correct spectral radius (avgLambda) for stretching.
368 */
369template<class VariableType, class T>
371 const Int& jPoint,
372 const Double& avgLambda,
373 const T& stretchParam,
374 const VariableType& solution) {
375
376 const auto lambda_i = gatherVariables(iPoint, solution.GetLambda());
377 const Double phi_i = pow(0.25*lambda_i/avgLambda, stretchParam);
378
379 const auto lambda_j = gatherVariables(jPoint, solution.GetLambda());
380 const Double phi_j = pow(0.25*lambda_j/avgLambda, stretchParam);
381
382 return 4*phi_i*phi_j / (phi_i + phi_j) * avgLambda;
383}
384
385/*!
386 * \brief Update of a flux Jacobian due to a scalar dissipation term.
387 */
388template<class VariableType, size_t nVar>
389FORCEINLINE void scalarDissipationJacobian(const VariableType& V,
390 const Double& gamma,
391 Double dissipConst,
392 MatrixDbl<nVar>& jac) {
393 /*--- Diagonal entries. ---*/
394 for (size_t iVar = 0; iVar < nVar-1; ++iVar) {
395 jac(iVar,iVar) += dissipConst;
396 }
397 jac(nVar-1,nVar-1) += dissipConst * gamma;
398
399 /*--- N-1 columns of last row. ---*/
400 dissipConst *= gamma-1.0;
401 for (size_t iDim = 0; iDim < VariableType::nDim; ++iDim) {
402 jac(nVar-1,iDim+1) -= dissipConst * V.velocity(iDim);
403 jac(nVar-1,0) += dissipConst * pow(V.velocity(iDim), 2);
404 }
405}
A templated matrix/vector-like object.
Definition C2DContainer.hpp:374
Class for defining the variables of the compressible Navier-Stokes solver.
Definition CNSVariable.hpp:38
su2double GetSensor(unsigned long iPoint) const
Get the pressure sensor.
Definition CVariable.hpp:965
A simple SIMD type relying on implicit vectorization, i.e. done by the compiler, explicitly vectorize...
Definition vectorization.hpp:89
@ Size
Definition vectorization.hpp:95
double passivedouble
Definition code_config.hpp:129
#define FORCEINLINE
Definition code_config.hpp:44
passivedouble su2double
Definition code_config.hpp:181
MatrixDbl< nDim+2 > pMatrix(const Double &gamma, const Double &density, const RandomAccessIterator &velocity, const Double &projVel, const Double &speedSound, const VectorDbl< nDim > &normal)
Compute and return the P tensor (compressible flow, ideal gas).
Definition common.hpp:136
MatrixDbl< nDim+2 > inviscidProjJac(const Double &gamma, RandomAccessIterator velocity, const Double &energy, const VectorDbl< nDim > &normal, const Double &scale)
Jacobian of the convective flux (compressible flow, ideal gas).
Definition common.hpp:280
MatrixDbl< nDim+2 > pMatrixInv(const Double &gamma, const Double &density, const RandomAccessIterator &velocity, const Double &projVel, const Double &speedSound, const VectorDbl< nDim > &normal)
Compute and return the inverse P tensor (compressible flow, ideal gas).
Definition common.hpp:198
VectorDbl< nDim+2 > inviscidProjFlux(const PrimVarType &V, const ConsVarType &U, const VectorDbl< nDim > &normal)
Convective projected (onto normal) flux (compressible flow).
Definition common.hpp:262
Double roeDissipation(const Int &iPoint, const Int &jPoint, const ENUM_ROELOWDISS type, const VariableType &solution)
(Low) Dissipation coefficient for Roe schemes.
Definition common.hpp:318
Double correctedSpectralRadius(const Int &iPoint, const Int &jPoint, const Double &avgLambda, const T &stretchParam, const VariableType &solution)
Correct spectral radius (avgLambda) for stretching.
Definition common.hpp:370
CPair< ReconVarType > reconstructPrimitives(const Int &iEdge, const Int &iPoint, const Int &jPoint, const su2double &gamma, const su2double &gasConst, const bool muscl, const su2double &kappa, const su2double &umusclRamp, const LIMITER limiterType, const CPair< PrimVarType > &V1st, const VectorDbl< nDim > &vector_ij, const VariableType &solution, Double &nonPhysical)
Retrieve primitive variables for points i/j, reconstructing them if needed.
Definition common.hpp:52
void scalarDissipationJacobian(const VariableType &V, const Double &gamma, Double dissipConst, MatrixDbl< nVar > &jac)
Update of a flux Jacobian due to a scalar dissipation term.
Definition common.hpp:389
FORCEINLINE ARRAY_T sqrt(const ARRAY_T &x)
Definition special_vectorization.hpp:116
FORCEINLINE ARRAY_T pow(const ARRAY_T &a, const ARRAY_T &b)
Definition special_vectorization.hpp:179
FORCEINLINE ARRAY_T sign(const ARRAY_T &x)
Definition special_vectorization.hpp:118
FORCEINLINE ARRAY_T abs(const ARRAY_T &x)
Definition special_vectorization.hpp:117
void muscl(typename CLaneTraits< Double >::Int iPoint, typename CLaneTraits< Double >::Int jPoint, const Vector< Double, nDim > &vector_ij, const Gradient_t &gradient, const Limiter_t &limiter, size_t iRow, CPair< VarType > &V, const CNonDeduced< Double > &kappa, const CNonDeduced< Double > &umusclRamp, size_t nVarGradRuntime)
U-MUSCL reconstruction of nVarGrad variables, from the gradient rows starting at iRow.
Definition util.hpp:508
auto dot(ForwardIterator iterator, const T *ptr) -> typename std::decay< decltype(*ptr)>::type
Dot product.
Definition util.hpp:203
Double gatherVariables(Int iPoint, const Container &vars, size_t iVar=0)
Gather a single variable, from column iVar (0 by default) of row iPoint of a 2D container,...
Definition util.hpp:277
@ V
Menter k-w SST model with vorticity production terms.
LIMITER
Types of slope limiters.
Definition option_structure.hpp:1038
ENUM_ROELOWDISS
Types of Roe Low Dissipation Schemes.
Definition option_structure.hpp:1668
@ NTS
Numerical Blending of Travin and Shur.
Definition option_structure.hpp:1671
@ NO_ROELOWDISS
No Roe Low Dissipation model.
Definition option_structure.hpp:1669
@ NTS_DUCROS
Numerical Blending of Travin and Shur + Ducros' Shock Sensor.
Definition option_structure.hpp:1672
@ FD_DUCROS
Numerical Blending based on DDES's F_d function + Ducros' Shock Sensor.
Definition option_structure.hpp:1673
@ FD
Numerical Blending based on DDES's F_d function.
Definition option_structure.hpp:1670
Simple pair type for i/j variables.
Definition util.hpp:130
T i
Definition util.hpp:131
T j
Definition util.hpp:131