ryujin 2.1.1 revision 0348cbb53a3e4b1da2a4c037e81f88f2d21ce219
equation_of_state_sesame.h
Go to the documentation of this file.
1//
2// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3// Copyright (C) 2023 by the ryujin authors
4//
5
6#pragma once
7
8#include <filesystem>
9
10#include <compile_time_options.h>
11
12#include "equation_of_state.h"
13#include "lazy.h"
14
15#include <deal.II/base/array_view.h>
16#include <deal.II/base/config.h>
17#include <deal.II/base/exceptions.h>
18#include <deal.II/base/parameter_acceptor.h>
19
20#ifdef WITH_EOSPAC
21#include "eos_Interface.h"
22#endif
23
24
25namespace ryujin
26{
27#ifdef WITH_EOSPAC
35 namespace eospac
36 {
42 enum class TableType : EOS_INTEGER {
47 p_rho_e = EOS_Pt_DUt,
52 e_rho_p = EOS_Ut_DPt,
53 };
54
55 class Interface
56 {
57 public:
64 Interface(const std::vector<std::tuple<EOS_INTEGER, TableType>> &tables)
65 {
66 n_tables_ = tables.size();
67
68 std::transform(std::begin(tables),
69 std::end(tables),
70 std::back_inserter(material_ids_),
71 [](const auto &it) { return std::get<0>(it); });
72
73 std::transform(std::begin(tables),
74 std::end(tables),
75 std::back_inserter(table_types_),
76 [](const auto &it) {
77 return static_cast<EOS_INTEGER>(std::get<1>(it));
78 });
79
80 table_handles_.resize(n_tables_);
81
82 /* create tables: */
83
84 EOS_INTEGER error_code;
85 eos_CreateTables(&n_tables_,
86 table_types_.data(),
87 material_ids_.data(),
88 table_handles_.data(),
89 &error_code);
90 check_tables("eos_CreateTables");
91
92 /* set table options: */
93
94 for (EOS_INTEGER i = 0; i < n_tables_; i++) {
95 // FIXME: refactor into options
96 eos_SetOption(
97 &table_handles_[i], &EOS_SMOOTH, EOS_NullPtr, &error_code);
98 check_error_code(error_code, "eos_SetOption", i);
99 }
100
101 /* load tables: */
102
103 eos_LoadTables(&n_tables_, table_handles_.data(), &error_code);
104 check_tables("eos_LoadTables");
105 }
106
110 ~Interface() noexcept
111 {
112 EOS_INTEGER error_code;
113 eos_DestroyTables(&n_tables_, table_handles_.data(), &error_code);
114 }
115
120 inline DEAL_II_ALWAYS_INLINE void
121 interpolate_values(const EOS_INTEGER &index,
122 const dealii::ArrayView<EOS_REAL> &F,
123 const dealii::ArrayView<EOS_REAL> &dFx,
124 const dealii::ArrayView<EOS_REAL> &dFy,
125 const dealii::ArrayView<const EOS_REAL> &X,
126 const dealii::ArrayView<const EOS_REAL> &Y)
127 {
128 Assert(index >= 0 && index < n_tables_,
129 dealii::ExcMessage("Table index out of range"));
130
131 EOS_INTEGER n_queries = F.size();
132
133#ifdef DEBUG
134 const decltype(dFx.size()) size = n_queries;
135 Assert(dFx.size() == size && dFy.size() == size && X.size() == size &&
136 Y.size() == size,
137 dealii::ExcMessage("vector sizes do not match"));
138#endif
139
140 EOS_INTEGER error_code;
141 eos_Interpolate(&table_handles_[index],
142 &n_queries,
143 const_cast<EOS_REAL *>(X.data()), /* sigh */
144 const_cast<EOS_REAL *>(Y.data()), /* sigh */
145 F.data(),
146 dFx.data(),
147 dFy.data(),
148 &error_code);
149 }
150
151 private:
155 std::vector<EOS_INTEGER> material_ids_;
156 std::vector<EOS_INTEGER> table_types_;
157 EOS_INTEGER n_tables_;
158 /* Mutable so that we can call eospac functions from a const context. */
159 mutable std::vector<EOS_INTEGER> table_handles_;
160
165 void check_error_code(
166 EOS_INTEGER error_code,
167 const std::string &routine,
168 EOS_INTEGER i = std::numeric_limits<EOS_INTEGER>::max()) const
169 {
170 if (error_code != EOS_OK) {
171 std::array<EOS_CHAR, EOS_MaxErrMsgLen> error_message;
172 eos_GetErrorMessage(&error_code, error_message.data());
173
174 std::stringstream exception_body;
175 exception_body << "Error: " << routine;
176 if (i != std::numeric_limits<EOS_INTEGER>::max())
177 exception_body << " (table " << i << ")";
178 exception_body << ": " << error_code << " - " << error_message.data()
179 << std::flush;
180 AssertThrow(false, dealii::ExcMessage(exception_body.str()));
181 }
182 }
183
184 void check_tables(const std::string &routine) const
185 {
186 for (EOS_INTEGER i = 0; i < n_tables_; i++) {
187 EOS_INTEGER table_error_code = EOS_OK;
188 eos_GetErrorCode(&table_handles_[i], &table_error_code);
189 if (table_error_code != EOS_OK) {
190 std::array<EOS_CHAR, EOS_MaxErrMsgLen> error_message;
191 eos_GetErrorMessage(&table_error_code, error_message.data());
192
193 std::stringstream exception_body;
194 exception_body << "Error: " << routine << " (table " << i
195 << "): " << table_error_code << " - "
196 << error_message.data() << std::flush;
197
198 AssertThrow(false, dealii::ExcMessage(exception_body.str()));
199 }
200 }
201 }
202 };
203 } // namespace eospac
204#endif
205
206 namespace EquationOfStateLibrary
207 {
219 class Sesame : public EquationOfState
220 {
221 public:
226
227#ifdef WITH_EOSPAC
228 Sesame(const std::string &subsection)
229 : EquationOfState("sesame", subsection)
230 {
231 material_id_ = 5030;
232 this->add_parameter(
233 "material id", material_id_, "The Sesame Material ID");
234
235 this->prefer_vector_interface_ = true;
236 }
237
238
239 double pressure(double rho, double e) const final
240 {
241 eospac_guard_.ensure_initialized([&]() {
242 this->set_up_database();
243 return true;
244 });
245
246 EOS_INTEGER index = 0;
247
248 double p, p_drho, p_de;
249 const double rho_scaled = rho / 1.0e3; // convert from Kg/m^3 to Mg/m^3
250 const double e_scaled = e / 1.0e6; // convert from J/kg to MJ/kg
251
252 eospac_interface_->interpolate_values(
253 index,
254 dealii::ArrayView<double>(&p, 1),
255 dealii::ArrayView<double>(&p_drho, 1),
256 dealii::ArrayView<double>(&p_de, 1),
257 dealii::ArrayView<const double>(&rho_scaled, 1),
258 dealii::ArrayView<const double>(&e_scaled, 1));
259
260 return 1.0e9 * p; // convert from GPa to Pa
261 }
262
263
264 void pressure(const dealii::ArrayView<double> &p,
265 const dealii::ArrayView<double> &rho,
266 const dealii::ArrayView<double> &e) const final
267 {
268 Assert(p.size() == rho.size() && rho.size() == e.size(),
269 dealii::ExcMessage("vectors have different size"));
270
271 eospac_guard_.ensure_initialized([&]() {
272 this->set_up_database();
273 return true;
274 });
275
276 EOS_INTEGER index = 0;
277
278 /* FIXME: this is not reentrant... */
279 thread_local static std::vector<double> p_drho;
280 thread_local static std::vector<double> p_de;
281 p_drho.resize(p.size());
282 p_de.resize(p.size());
283
284 // convert from Kg/m^3 to Mg/m^3
285 std::transform(std::begin(rho),
286 std::end(rho),
287 std::begin(rho),
288 [](double rho) { return rho / 1.0e3; });
289
290 // convert from J/kg to MJ/kg
291 std::transform(std::begin(e), //
292 std::end(e),
293 std::begin(e),
294 [](auto e) { return e / 1.0e6; });
295
296 eospac_interface_->interpolate_values(index,
297 p,
298 dealii::ArrayView<double>(p_drho),
299 dealii::ArrayView<double>(p_de),
300 rho,
301 e);
302
303 // convert from GPa to Pa
304 std::transform(std::begin(p), //
305 std::end(p),
306 std::begin(p),
307 [](auto it) { return it * 1.0e9; });
308 }
309
310
311 double specific_internal_energy(double rho, double p) const final
312 {
313 eospac_guard_.ensure_initialized([&]() {
314 this->set_up_database();
315 return true;
316 });
317
318 EOS_INTEGER index = 1;
319
320 double e, e_drho, e_dp;
321 const double rho_scaled = rho / 1.0e3; // convert from Kg/M^3 to Mg/M^3
322 const double p_scaled = p / 1.0e9; // convert from Pa to GPa
323
324 eospac_interface_->interpolate_values(
325 index,
326 dealii::ArrayView<double>(&e, 1),
327 dealii::ArrayView<double>(&e_drho, 1),
328 dealii::ArrayView<double>(&e_dp, 1),
329 dealii::ArrayView<const double>(&rho_scaled, 1),
330 dealii::ArrayView<const double>(&p_scaled, 1));
331
332 return 1.0e6 * e; // convert from MJ/kg to J/kg
333 }
334
335
336 void
337 specific_internal_energy(const dealii::ArrayView<double> &e,
338 const dealii::ArrayView<double> &rho,
339 const dealii::ArrayView<double> &p) const final
340 {
341 Assert(e.size() == rho.size() && rho.size() == p.size(),
342 dealii::ExcMessage("vectors have different size"));
343
344 eospac_guard_.ensure_initialized([&]() {
345 this->set_up_database();
346 return true;
347 });
348
349 EOS_INTEGER index = 1;
350
351 /* FIXME: this is not reentrant... */
352 thread_local static std::vector<double> e_drho;
353 thread_local static std::vector<double> e_dp;
354 e_drho.resize(e.size());
355 e_dp.resize(e.size());
356
357 // convert from Kg/m^3 to Mg/m^3
358 std::transform(std::begin(rho),
359 std::end(rho),
360 std::begin(rho),
361 [](double rho) { return rho / 1.0e3; });
362
363 // convert from Pa to GPa
364 std::transform(std::begin(p), //
365 std::end(p),
366 std::begin(p),
367 [](auto it) { return it / 1.0e9; });
368
369 eospac_interface_->interpolate_values(index,
370 e,
371 dealii::ArrayView<double>(e_drho),
372 dealii::ArrayView<double>(e_dp),
373 rho,
374 p);
375
376 // convert from MJ/kg to J/kg
377 std::transform(std::begin(e), //
378 std::end(e),
379 std::begin(e),
380 [](auto e) { return e * 1.0e6; });
381 }
382
383 /* FIXME: Implement table look up for temperature. Need to think about
384 * whether it should be T(rho, e) or T(rho, p). */
385
386 double temperature(double /*rho*/, double /*e*/) const final
387 {
388 eospac_guard_.ensure_initialized([&]() {
389 this->set_up_database();
390 return true;
391 });
392
393 AssertThrow(false, dealii::ExcInternalError());
394 __builtin_trap();
395 }
396
397
398 void temperature(const dealii::ArrayView<double> & /*temp*/,
399 const dealii::ArrayView<double> & /*rho*/,
400 const dealii::ArrayView<double> & /*e*/) const final
401 {
402 eospac_guard_.ensure_initialized([&]() {
403 this->set_up_database();
404 return true;
405 });
406
407 AssertThrow(false, dealii::ExcInternalError());
408 __builtin_trap();
409 }
410
411
412 double speed_of_sound(double /*rho*/, double /*e*/) const final
413 {
414 eospac_guard_.ensure_initialized([&]() {
415 this->set_up_database();
416 return true;
417 });
418
419 AssertThrow(false, dealii::ExcInternalError());
420 __builtin_trap();
421 }
422
423
424 void speed_of_sound(const dealii::ArrayView<double> & /*c*/,
425 const dealii::ArrayView<double> & /*rho*/,
426 const dealii::ArrayView<double> & /*e*/) const final
427 {
428 eospac_guard_.ensure_initialized([&]() {
429 this->set_up_database();
430 return true;
431 });
432
433 AssertThrow(false, dealii::ExcInternalError());
434 __builtin_trap();
435 }
436
437 private:
442 //
443 void set_up_database() const
444 {
445 AssertThrow(
446 std::filesystem::exists("sesameFilesDir.txt"),
447 dealii::ExcMessage(
448 "For EOSPAC to find the sesame database, we assume that there "
449 "exists a file named 'sesameFilesDir.txt' in the current "
450 "simulation directory. This file should list the path to the "
451 "sesame database. See the EOSPAC manual for more "
452 "information."));
453 const std::vector<std::tuple<EOS_INTEGER, eospac::TableType>> tables{
454 {material_id_, eospac::TableType::p_rho_e},
455 {material_id_, eospac::TableType::e_rho_p},
456 };
457
458 eospac_interface_ = std::make_unique<eospac::Interface>(tables);
459 }
460
461 Lazy<bool> eospac_guard_;
462 mutable std::unique_ptr<eospac::Interface> eospac_interface_;
463
465
469
470 EOS_INTEGER material_id_;
471
473
474#else /* WITHOUT_EOSPAC */
475
476 /* We do not have eospac support */
477 Sesame(const std::string &subsection)
478 : EquationOfState("Sesame", subsection)
479 {
480 }
481
482 static constexpr auto message =
483 "ryujin has to be configured with eospac support in order to use "
484 "the Sesame EOS database";
485
486 double pressure(double /*rho*/, double /*internal_energy*/) const final
487 {
488 AssertThrow(false, dealii::ExcMessage(message));
489 __builtin_trap();
490 }
491
492 double specific_internal_energy(double /*rho*/, double /*p*/) const final
493 {
494 AssertThrow(false, dealii::ExcMessage(message));
495 __builtin_trap();
496 }
497
498 double temperature(double /*rho*/, double /*e*/) const final
499 {
500 AssertThrow(false, dealii::ExcMessage(message));
501 __builtin_trap();
502 }
503
504 double speed_of_sound(double /*rho*/, double /*e*/) const final
505 {
506 AssertThrow(false, dealii::ExcMessage(message));
507 __builtin_trap();
508 }
509#endif
510 };
511 } // namespace EquationOfStateLibrary
512} // namespace ryujin
virtual double specific_internal_energy(double rho, double p) const =0
virtual double pressure(double rho, double e) const =0
virtual double speed_of_sound(double rho, double e) const =0
virtual double temperature(double rho, double e) const =0
EquationOfState(const std::string &name, const std::string &subsection)
double pressure(double, double) const final
double speed_of_sound(double, double) const final
double temperature(double, double) const final
double specific_internal_energy(double, double) const final