https://mooseframework.inl.gov
Loading...
Searching...
No Matches
Functions
CaloricallyImperfectGasTest.C File Reference

Go to the source code of this file.

Functions

 TEST_F (CaloricallyImperfectGasTest, testAll)
 Verify that the fluid name is correctly returned.
 
 TEST_F (CaloricallyImperfectGasTest, nonMonotonicError1)
 
 TEST_F (CaloricallyImperfectGasTest, nonMonotonicError2)
 
 TEST_F (CaloricallyImperfectGasTest, compareWithIdeal)
 
 TEST_F (CaloricallyImperfectGasTest, soundSpeedVaryingGamma)
 Verify the sound speed derivatives for an internal energy that is quadratic in temperature, so that the specific heat ratio varies with the internal energy.
 
 TEST_F (CaloricallyImperfectGasTest, lookupTableBounds)
 Verify the lookup tables at and beyond their bounds.
 
 TEST_F (CaloricallyImperfectGasTest, derivativesAtEdgeStates)
 Verify derivatives that were computed with relative finite-difference steps, at states where the step would vanish (s = 0) or leave the table (T = max_temperature)
 

Function Documentation

◆ TEST_F() [1/7]

TEST_F ( CaloricallyImperfectGasTest  ,
compareWithIdeal   
)

Definition at line 548 of file CaloricallyImperfectGasTest.C.

549{
550 const IdealGasFluidProperties * ideal;
551 const CaloricallyImperfectGas * compare_with_ideal;
552 // compare ideal gas and calorically imperfect gas
553 InputParameters ideal_uo_pars = _factory.getValidParams("IdealGasFluidProperties");
554 ideal_uo_pars.set<Real>("molar_mass") = 0.002;
555 ideal_uo_pars.set<Real>("gamma") = 1.41;
556 _fe_problem->addUserObject("IdealGasFluidProperties", "ideal_fp", ideal_uo_pars);
557 ideal = &_fe_problem->getUserObject<IdealGasFluidProperties>("ideal_fp");
558
559 Real Ru = 8.31446261815324;
560 Real Rs = Ru / 0.002;
561 Real gamma = 1.41;
562 Real cp_val = gamma / (gamma - 1) * Rs;
563 Real cv_val = cp_val / gamma;
564 std::vector<Real> temps = {0.0, 500.0};
565 std::vector<Real> internal_energies = {0.0, 500.0 * cv_val};
566
567 InputParameters lin_e_fn_params = _factory.getValidParams("PiecewiseLinear");
568 lin_e_fn_params.set<std::vector<Real>>("x") = temps;
569 lin_e_fn_params.set<std::vector<Real>>("y") = internal_energies;
570 _fe_problem->addFunction("PiecewiseLinear", "lin_e_fn", lin_e_fn_params);
571
572 InputParameters compare_uo_pars = _factory.getValidParams("CaloricallyImperfectGas");
573 compare_uo_pars.set<Real>("molar_mass") = 0.002;
574 compare_uo_pars.set<FunctionName>("e") = "lin_e_fn";
575 compare_uo_pars.set<FunctionName>("mu") = "default_fn";
576 compare_uo_pars.set<FunctionName>("k") = "default_fn";
577 compare_uo_pars.set<Real>("min_temperature") = 100.0;
578 compare_uo_pars.set<Real>("max_temperature") = 500.0;
579 _fe_problem->addUserObject("CaloricallyImperfectGas", "compare_fp", compare_uo_pars);
580 compare_with_ideal = &_fe_problem->getUserObject<CaloricallyImperfectGas>("compare_fp");
581
582 const_cast<CaloricallyImperfectGas *>(compare_with_ideal)->initialSetup();
583
584 Real T = 325.0;
585 Real p = 1.0e6;
586
587 // test all functions that provide x_from_p_T, x_from_v_e, e_from_v_h, e_from_p_rho
588 {
589 Real v = ideal->v_from_p_T(p, T);
590 Real e = ideal->e_from_p_T(p, T);
591 Real rho = ideal->rho_from_p_T(p, T);
592 Real h = ideal->h_from_p_T(p, T);
593 REL_TEST(ideal->c_from_p_T(p, T), compare_with_ideal->c_from_p_T(p, T), 1e-5);
594 REL_TEST(ideal->rho_from_p_T(p, T), compare_with_ideal->rho_from_p_T(p, T), 1e-5);
595 REL_TEST(ideal->h_from_p_T(p, T), compare_with_ideal->h_from_p_T(p, T), 1e-5);
596 REL_TEST(ideal->e_from_p_T(p, T), compare_with_ideal->e_from_p_T(p, T), 1e-5);
597 REL_TEST(ideal->cv_from_p_T(p, T), compare_with_ideal->cv_from_p_T(p, T), 1e-5);
598 REL_TEST(ideal->cp_from_p_T(p, T), compare_with_ideal->cp_from_p_T(p, T), 1e-5);
599 REL_TEST(ideal->T_from_v_e(v, e), compare_with_ideal->T_from_v_e(v, e), 1e-5);
600 REL_TEST(ideal->c_from_v_e(v, e), compare_with_ideal->c_from_v_e(v, e), 1e-5);
601 REL_TEST(ideal->cv_from_v_e(v, e), compare_with_ideal->cv_from_v_e(v, e), 1e-5);
602 REL_TEST(ideal->cp_from_v_e(v, e), compare_with_ideal->cp_from_v_e(v, e), 1e-5);
603 REL_TEST(ideal->e_from_v_h(v, h), compare_with_ideal->e_from_v_h(v, h), 1e-5);
604 REL_TEST(ideal->e_from_p_rho(p, rho), compare_with_ideal->e_from_p_rho(p, rho), 1e-5);
605 REL_TEST(ideal->e_from_T_v(T, v), compare_with_ideal->e_from_T_v(T, v), 1e-5);
606 REL_TEST(ideal->p_from_T_v(T, v), compare_with_ideal->p_from_T_v(T, v), 1e-5);
607 REL_TEST(ideal->gamma_from_p_T(p, T), compare_with_ideal->gamma_from_p_T(p, T), 1e-5);
608 REL_TEST(ideal->gamma_from_v_e(v, e), compare_with_ideal->gamma_from_v_e(v, e), 1e-5);
609 }
610
611 // test derivatives for c_from_v_e
612 {
613 Real v = ideal->v_from_p_T(p, T);
614 Real e = ideal->e_from_p_T(p, T);
615 Real c = 0, dc_dv = 0, dc_de = 0;
616 ideal->c_from_v_e(v, e, c, dc_dv, dc_de);
617 Real c2 = 0, dc_dv2 = 0, dc_de2 = 0;
618 compare_with_ideal->c_from_v_e(v, e, c2, dc_dv2, dc_de2);
619 REL_TEST(dc_dv, dc_dv2, 1e-5);
620 REL_TEST(dc_de, dc_de2, 1e-5);
621 }
622
623 // test derivatives for p_from_v_e
624 {
625 Real v = ideal->v_from_p_T(p, T);
626 Real e = ideal->e_from_p_T(p, T);
627 Real pp = 0, dp_dv = 0, dp_de = 0;
628 ideal->p_from_v_e(v, e, pp, dp_dv, dp_de);
629 Real pp2 = 0, dp_dv2 = 0, dp_de2 = 0;
630 compare_with_ideal->p_from_v_e(v, e, pp2, dp_dv2, dp_de2);
631 REL_TEST(dp_dv, dp_dv2, 1e-5);
632 REL_TEST(dp_de, dp_de2, 1e-5);
633 }
634
635 // test derivatives for T_from_v_e
636 {
637 Real v = ideal->v_from_p_T(p, T);
638 Real e = ideal->e_from_p_T(p, T);
639 Real TT = 0, dT_dv = 0, dT_de = 0;
640 ideal->T_from_v_e(v, e, TT, dT_dv, dT_de);
641 Real TT2 = 0, dT_dv2 = 0, dT_de2 = 0;
642 compare_with_ideal->T_from_v_e(v, e, TT2, dT_dv2, dT_de2);
643 REL_TEST(dT_dv, dT_dv2, 1e-5);
644 REL_TEST(dT_de, dT_de2, 1e-5);
645 }
646
647 // test derivatives for e_from_v_h
648 {
649 Real v = ideal->v_from_p_T(p, T);
650 Real h = ideal->h_from_p_T(p, T);
651 Real ee = 0, de_dv = 0, de_dh = 0;
652 ideal->e_from_v_h(v, h, ee, de_dv, de_dh);
653 Real ee2 = 0, de_dv2 = 0, de_dh2 = 0;
654 compare_with_ideal->e_from_v_h(v, h, ee2, de_dv2, de_dh2);
655 REL_TEST(de_dv, de_dv2, 1e-5);
656 REL_TEST(de_dh, de_dh2, 1e-5);
657 }
658}
const Real p
const double rho
const double T
const double v
A calorically imperfect gas fluid property class This fluid property assumes that internal energy is ...
virtual Real e_from_v_h(Real v, Real h) const override
virtual Real p_from_v_e(Real v, Real e) const override
virtual Real c_from_p_T(Real p, Real T) const override
virtual Real cv_from_v_e(Real v, Real e) const override
virtual Real gamma_from_p_T(Real p, Real T) const override
virtual Real cp_from_v_e(Real v, Real e) const override
virtual Real e_from_p_T(Real p, Real T) const override
virtual Real h_from_p_T(Real p, Real T) const override
virtual Real e_from_T_v(Real T, Real v) const override
virtual Real T_from_v_e(Real v, Real e) const override
virtual Real cv_from_p_T(Real p, Real T) const override
virtual Real c_from_v_e(Real v, Real e) const override
virtual Real p_from_T_v(Real T, Real v) const override
virtual Real cp_from_p_T(Real p, Real T) const override
virtual Real rho_from_p_T(Real p, Real T) const override
virtual Real gamma_from_v_e(Real v, Real e) const override
Ideal gas fluid properties Default parameters are for air at atmospheric pressure and temperature.
virtual Real p_from_v_e(Real v, Real e) const override
virtual Real c_from_v_e(Real v, Real e) const override
virtual Real e_from_v_h(Real v, Real h) const override
virtual Real T_from_v_e(Real v, Real e) const override
virtual Real cv_from_p_T(Real p, Real T) const override
virtual Real e_from_p_rho(Real p, Real rho) const override
virtual Real rho_from_p_T(Real p, Real T) const override
virtual Real e_from_T_v(Real T, Real v) const override
virtual Real cp_from_p_T(Real p, Real T) const override
virtual Real c_from_p_T(Real p, Real T) const override
virtual Real gamma_from_v_e(Real v, Real e) const override
virtual Real p_from_T_v(Real T, Real v) const override
virtual Real e_from_p_T(Real p, Real T) const override
virtual Real gamma_from_p_T(Real p, Real T) const override
virtual Real h_from_p_T(Real p, Real T) const override
virtual Real cp_from_v_e(Real v, Real e) const override
virtual Real cv_from_v_e(Real v, Real e) const override
T & set(const std::string &name, bool quiet_mode=false)
const T & getUserObject(const std::string &param_name, bool is_dependency=true) const
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real

◆ TEST_F() [2/7]

TEST_F ( CaloricallyImperfectGasTest  ,
derivativesAtEdgeStates   
)

Verify derivatives that were computed with relative finite-difference steps, at states where the step would vanish (s = 0) or leave the table (T = max_temperature)

Definition at line 741 of file CaloricallyImperfectGasTest.C.

742{
743 InputParameters e_fn_params = _factory.getValidParams("ParsedFunction");
744 e_fn_params.set<std::string>("expression") = "3000 * t + 2 * t * t";
745 _fe_problem->addFunction("ParsedFunction", "e_edge_fn", e_fn_params);
746 _fe_problem->getFunction("e_edge_fn").initialSetup();
747
748 InputParameters uo_pars = _factory.getValidParams("CaloricallyImperfectGas");
749 uo_pars.set<Real>("molar_mass") = 0.002;
750 uo_pars.set<FunctionName>("e") = "e_edge_fn";
751 uo_pars.set<FunctionName>("mu") = "e_edge_fn";
752 uo_pars.set<FunctionName>("k") = "e_edge_fn";
753 uo_pars.set<Real>("min_temperature") = 100.0;
754 uo_pars.set<Real>("max_temperature") = 500.0;
755 uo_pars.set<Real>("temperature_resolution") = 0.01;
756 _fe_problem->addUserObject("CaloricallyImperfectGas", "fp_edge", uo_pars);
757 auto & fp = _fe_problem->getUserObject<CaloricallyImperfectGas>("fp_edge");
758 fp.initialSetup();
759
760 // (dp/dh)_s = rho and (dp/ds)_h = -T rho, from dh = T ds + v dp
761 const Real T = 300.0;
762 const Real v = 1.0 / fp.rho_from_p_T(1e5, T);
763 const Real h = fp.h_from_T_v(T, v);
764 // The entropy reference makes s = 0 at the state with Z(T) + R ln(v) = 0
765 const Real s0 = 0.0;
766 Real p, dp_dh, dp_ds;
767 fp.p_from_h_s(h, s0, p, dp_dh, dp_ds);
768 const Real T0 = fp.T_from_p_h(p, h);
769 const Real rho0 = fp.rho_from_p_T(p, T0);
770 REL_TEST(dp_dh, rho0, REL_TOL_DERIVATIVE);
771 REL_TEST(dp_ds, -T0 * rho0, REL_TOL_DERIVATIVE);
772
773 // Temperature derivatives at the upper bound of the table must not leave the table
774 Real cp, dcp_dp, dcp_dT;
775 fp.cp_from_p_T(1e5, 500.0, cp, dcp_dp, dcp_dT);
776 REL_TEST(dcp_dT, 4.0, 1e-4);
777 Real mu, dmu_dp, dmu_dT;
778 fp.mu_from_p_T(1e5, 500.0, mu, dmu_dp, dmu_dT);
779 REL_TEST(dmu_dT, 3000.0 + 4.0 * 500.0, 1e-4);
780}
const double mu

◆ TEST_F() [3/7]

TEST_F ( CaloricallyImperfectGasTest  ,
lookupTableBounds   
)

Verify the lookup tables at and beyond their bounds.

Definition at line 697 of file CaloricallyImperfectGasTest.C.

698{
699 const bool original_throw_on_warning = Moose::_throw_on_warning;
701
702 InputParameters e_fn_params = _factory.getValidParams("PiecewiseLinear");
703 e_fn_params.set<std::vector<Real>>("x") = {100, 500};
704 e_fn_params.set<std::vector<Real>>("y") = {1e6, 5e6};
705 _fe_problem->addFunction("PiecewiseLinear", "e_lin_fn", e_fn_params);
706
707 InputParameters uo_pars = _factory.getValidParams("CaloricallyImperfectGas");
708 uo_pars.set<Real>("molar_mass") = 0.002;
709 uo_pars.set<FunctionName>("e") = "e_lin_fn";
710 uo_pars.set<FunctionName>("mu") = "default_fn";
711 uo_pars.set<FunctionName>("k") = "default_fn";
712 uo_pars.set<Real>("min_temperature") = 100.0;
713 uo_pars.set<Real>("max_temperature") = 500.0;
714 uo_pars.set<Real>("temperature_resolution") = 1.0;
715 uo_pars.set<bool>("out_of_bound_error") = false;
716 _fe_problem->addUserObject("CaloricallyImperfectGas", "fp_bounds", uo_pars);
717 auto & fp = _fe_problem->getUserObject<CaloricallyImperfectGas>("fp_bounds");
718 fp.initialSetup();
719
720 const Real v = 1.0;
721 const Real p = 1e5;
722 // Upper bound of the T(e), T(h) and Z(T) tables
723 REL_TEST(fp.T_from_v_e(v, 5e6), 500.0, REL_TOL_CONSISTENCY);
724 REL_TEST(fp.T_from_p_h(p, fp.h_from_p_T(p, 500.0)), 500.0, REL_TOL_CONSISTENCY);
725 EXPECT_TRUE(std::isfinite(fp.s_from_p_T(p, 500.0)));
726 // Below and above the tables, the values are clamped to the bounds
727 REL_TEST(fp.T_from_v_e(v, 0.5e6), 100.0, REL_TOL_CONSISTENCY);
728 REL_TEST(fp.T_from_v_e(v, 6e6), 500.0, REL_TOL_CONSISTENCY);
729 // s(T, v) = Z(T) + R ln(v), so at fixed v the entropy outside the table equals that at
730 // the nearest bound
731 REL_TEST(fp.s_from_T_v(50.0, v), fp.s_from_T_v(100.0, v), REL_TOL_CONSISTENCY);
732 REL_TEST(fp.s_from_T_v(600.0, v), fp.s_from_T_v(500.0, v), REL_TOL_CONSISTENCY);
733
734 Moose::_throw_on_warning = original_throw_on_warning;
735}
bool _throw_on_warning

◆ TEST_F() [4/7]

TEST_F ( CaloricallyImperfectGasTest  ,
nonMonotonicError1   
)

Definition at line 482 of file CaloricallyImperfectGasTest.C.

483{
484 // Testing case where e(T) is not monotonic
485 const CaloricallyImperfectGas * fp_bad_e_fn;
486 std::vector<Real> T = {100, 200, 300, 400, 500};
487 std::vector<Real> bad_e = {2859400, 8578200, 17156400, 8578200, 42891000};
488 InputParameters bad_e_fn_params = _factory.getValidParams("PiecewiseLinear");
489 bad_e_fn_params.set<std::vector<Real>>("x") = T;
490 bad_e_fn_params.set<std::vector<Real>>("y") = bad_e;
491 _fe_problem->addFunction("PiecewiseLinear", "bad_e_fn", bad_e_fn_params);
492
493 InputParameters uo_pars_bad_e_fn = _factory.getValidParams("CaloricallyImperfectGas");
494 uo_pars_bad_e_fn.set<Real>("molar_mass") = 0.002;
495 uo_pars_bad_e_fn.set<FunctionName>("e") = "bad_e_fn";
496 uo_pars_bad_e_fn.set<FunctionName>("mu") = "default_fn";
497 uo_pars_bad_e_fn.set<FunctionName>("k") = "default_fn";
498 uo_pars_bad_e_fn.set<Real>("min_temperature") = 100.0;
499 uo_pars_bad_e_fn.set<Real>("max_temperature") = 500.0;
500 _fe_problem->addUserObject("CaloricallyImperfectGas", "fp_bad_e_fn", uo_pars_bad_e_fn);
501 fp_bad_e_fn = &_fe_problem->getUserObject<CaloricallyImperfectGas>("fp_bad_e_fn");
502
503 try
504 {
505 const_cast<CaloricallyImperfectGas *>(fp_bad_e_fn)->initialSetup();
506 FAIL();
507 }
508 catch (const std::exception & err)
509 {
510 std::size_t pos = std::string(err.what()).find("e(T) is not monotonically increasing with T");
511 ASSERT_TRUE(pos != std::string::npos);
512 }
513}
OStreamProxy err(std::cerr)

◆ TEST_F() [5/7]

TEST_F ( CaloricallyImperfectGasTest  ,
nonMonotonicError2   
)

Definition at line 515 of file CaloricallyImperfectGasTest.C.

516{
517 // test for bad temperature values that violate min/max temperature
518 const CaloricallyImperfectGas * fp_bad_e_fn2;
519 std::vector<Real> e = {1825110, 5272540, 10342290, 17034360, 25348750};
520 std::vector<Real> bad_T = {150, 200, 300, 400, 500};
521 InputParameters bad_e_fn_params2 = _factory.getValidParams("PiecewiseLinear");
522 bad_e_fn_params2.set<std::vector<Real>>("x") = bad_T;
523 bad_e_fn_params2.set<std::vector<Real>>("y") = e;
524 _fe_problem->addFunction("PiecewiseLinear", "bad_e_fn2", bad_e_fn_params2);
525
526 InputParameters uo_pars_bad_e_fn2 = _factory.getValidParams("CaloricallyImperfectGas");
527 uo_pars_bad_e_fn2.set<Real>("molar_mass") = 0.002;
528 uo_pars_bad_e_fn2.set<FunctionName>("e") = "bad_e_fn2";
529 uo_pars_bad_e_fn2.set<FunctionName>("mu") = "default_fn";
530 uo_pars_bad_e_fn2.set<FunctionName>("k") = "default_fn";
531 uo_pars_bad_e_fn2.set<Real>("min_temperature") = 100.0;
532 uo_pars_bad_e_fn2.set<Real>("max_temperature") = 500.0;
533 _fe_problem->addUserObject("CaloricallyImperfectGas", "fp_bad_e_fn2", uo_pars_bad_e_fn2);
534 fp_bad_e_fn2 = &_fe_problem->getUserObject<CaloricallyImperfectGas>("fp_bad_e_fn2");
535
536 try
537 {
538 const_cast<CaloricallyImperfectGas *>(fp_bad_e_fn2)->initialSetup();
539 FAIL();
540 }
541 catch (const std::exception & err)
542 {
543 std::size_t pos = std::string(err.what()).find("e(T) is not monotonically increasing with T");
544 ASSERT_TRUE(pos != std::string::npos);
545 }
546}

◆ TEST_F() [6/7]

TEST_F ( CaloricallyImperfectGasTest  ,
soundSpeedVaryingGamma   
)

Verify the sound speed derivatives for an internal energy that is quadratic in temperature, so that the specific heat ratio varies with the internal energy.

Definition at line 664 of file CaloricallyImperfectGasTest.C.

665{
666 // e(T) = 3000 T + 2 T^2, so cv = 3000 + 4 T and the specific heat ratio vary continuously
667 InputParameters e_fn_params = _factory.getValidParams("ParsedFunction");
668 e_fn_params.set<std::string>("expression") = "3000 * t + 2 * t * t";
669 _fe_problem->addFunction("ParsedFunction", "e_quad_fn", e_fn_params);
670 _fe_problem->getFunction("e_quad_fn").initialSetup();
671
672 InputParameters uo_pars = _factory.getValidParams("CaloricallyImperfectGas");
673 uo_pars.set<Real>("molar_mass") = 0.002;
674 uo_pars.set<FunctionName>("e") = "e_quad_fn";
675 uo_pars.set<FunctionName>("mu") = "default_fn";
676 uo_pars.set<FunctionName>("k") = "default_fn";
677 uo_pars.set<Real>("min_temperature") = 100.0;
678 uo_pars.set<Real>("max_temperature") = 500.0;
679 uo_pars.set<Real>("temperature_resolution") = 0.01;
680 _fe_problem->addUserObject("CaloricallyImperfectGas", "fp_quad", uo_pars);
681 auto & fp = _fe_problem->getUserObject<CaloricallyImperfectGas>("fp_quad");
682 fp.initialSetup();
683
684 const Real T = 300.0;
685 const Real p = 1e5;
686 const Real v = 1.0 / fp.rho_from_p_T(p, T);
687 const Real e = fp.e_from_p_T(p, T);
688
689 // The tolerance accounts for the linear interpolation of the T(e) lookup table
690 DERIV_TEST_CUSTOM_PERTURBATION(fp.c_from_v_e, v, e, 1e-4, 1e-4);
691 DERIV_TEST_CUSTOM_PERTURBATION(fp.gamma_from_v_e, v, e, 1e-4, 1e-4);
692}

◆ TEST_F() [7/7]

TEST_F ( CaloricallyImperfectGasTest  ,
testAll   
)

Verify that the fluid name is correctly returned.

Definition at line 16 of file CaloricallyImperfectGasTest.C.

17{
19 std::vector<Real> T = {100, 200, 300, 400, 500};
20 std::vector<Real> e = {1825110, 5272540, 10342290, 17034360, 25348750};
21 std::vector<Real> T2 = {100, 500};
22 std::vector<Real> mu = {1, 6};
23 std::vector<Real> k = {11, 1};
24
25 InputParameters e_fn_params = _factory.getValidParams("PiecewiseLinear");
26 e_fn_params.set<std::vector<Real>>("x") = T;
27 e_fn_params.set<std::vector<Real>>("y") = e;
28 _fe_problem->addFunction("PiecewiseLinear", "e_fn", e_fn_params);
29
30 InputParameters mu_fn_params = _factory.getValidParams("PiecewiseLinear");
31 mu_fn_params.set<std::vector<Real>>("x") = T2;
32 mu_fn_params.set<std::vector<Real>>("y") = mu;
33 _fe_problem->addFunction("PiecewiseLinear", "mu_fn", mu_fn_params);
34
35 InputParameters k_fn_params = _factory.getValidParams("PiecewiseLinear");
36 k_fn_params.set<std::vector<Real>>("x") = T2;
37 k_fn_params.set<std::vector<Real>>("y") = k;
38 _fe_problem->addFunction("PiecewiseLinear", "k_fn", k_fn_params);
39
40 InputParameters uo_pars = _factory.getValidParams("CaloricallyImperfectGas");
41 uo_pars.set<Real>("molar_mass") = 0.002;
42 uo_pars.set<FunctionName>("e") = "e_fn";
43 uo_pars.set<FunctionName>("mu") = "mu_fn";
44 uo_pars.set<FunctionName>("k") = "k_fn";
45 uo_pars.set<Real>("min_temperature") = 100.0;
46 uo_pars.set<Real>("max_temperature") = 500.0;
47 uo_pars.set<Real>("temperature_resolution") = 0.01;
48 _fe_problem->addUserObject("CaloricallyImperfectGas", "fp", uo_pars);
49 fp = &_fe_problem->getUserObject<CaloricallyImperfectGas>("fp");
50
51 const_cast<CaloricallyImperfectGas *>(fp)->initialSetup();
52
53 Real min_T = 100.0;
54 Real max_T = 500.0;
55 unsigned int np = 200;
56 Real dT = (max_T - min_T) / ((Real)np - 1.0);
57 Real Ru = 8.31446261815324;
58 Real Rs = Ru / 0.002;
59
60 // Consistency checks
61 {
62 for (unsigned int j = 1; j < np - 1; ++j)
63 {
64 Real T = min_T + j * dT;
65 Real p = 1.0e6;
66 const Real rho = fp->rho_from_p_T(p, T);
67 const Real v = 1.0 / rho;
68 Real h = fp->h_from_p_T(p, T);
69 Real e = fp->e_from_p_T(p, T);
70 Real cp = fp->cp_from_p_T(p, T);
71 Real cv = fp->cv_from_p_T(p, T);
72 Real k = fp->k_from_p_T(p, T);
73 Real mu = fp->mu_from_p_T(p, T);
74 Real s = fp->s_from_p_T(p, T);
75
76 // test rho_from_p_s
77 REL_TEST(fp->rho_from_p_s(p, s), rho, 10.0 * REL_TOL_CONSISTENCY);
78
79 // test e_from_x_y functions
80 REL_TEST(fp->e_from_v_h(v, h), e, 10.0 * REL_TOL_CONSISTENCY);
81 REL_TEST(fp->e_from_p_rho(p, rho), e, 10.0 * REL_TOL_CONSISTENCY);
82 REL_TEST(fp->e_from_T_v(T, v), e, 10.0 * REL_TOL_CONSISTENCY);
83
84 // test cv_x_y functions
85 REL_TEST(fp->cv_from_T_v(T, v), cv, 10.0 * REL_TOL_CONSISTENCY);
86 REL_TEST(fp->cv_from_v_e(v, e), cv, 10.0 * REL_TOL_CONSISTENCY);
87
88 // test cp_x_y functions
89 REL_TEST(fp->cp_from_v_e(v, e), cp, 10.0 * REL_TOL_CONSISTENCY);
90
91 // test h_from_x_y functions
92 REL_TEST(fp->h_from_T_v(T, v), h, 10.0 * REL_TOL_CONSISTENCY);
93
94 // test p_from_x_y functions
95 REL_TEST(fp->p_from_v_e(v, e), p, 10.0 * REL_TOL_CONSISTENCY);
96 REL_TEST(fp->p_from_T_v(T, v), p, 10.0 * REL_TOL_CONSISTENCY);
97
98 // test T_from_x_y functions
99 REL_TEST(fp->T_from_p_h(p, h), T, 10.0 * REL_TOL_CONSISTENCY);
100 REL_TEST(fp->T_from_v_e(v, e), T, 10.0 * REL_TOL_CONSISTENCY);
101
102 // test k_from_x_y functions
103 REL_TEST(fp->k_from_v_e(v, e), k, 10.0 * REL_TOL_CONSISTENCY);
104
105 // test mu_from_x_y functions
106 REL_TEST(fp->mu_from_v_e(v, e), mu, 10.0 * REL_TOL_CONSISTENCY);
107 }
108 }
109
110 // AD consistency checks
111 {
112 for (unsigned int j = 1; j < np - 1; ++j)
113 {
114 Real T = min_T + j * dT;
115 Real p = 1.0e6;
116 const Real rho = fp->rho_from_p_T(p, T);
117 const Real v = 1.0 / rho;
118 Real e = fp->e_from_p_T(p, T);
119 Real cv = fp->cv_from_p_T(p, T);
120 Real c = fp->c_from_p_T(p, T);
121
122 ADReal ad_e = e;
123 ADReal ad_v = v;
124 ADReal ad_p = fp->p_from_v_e(ad_v, ad_e);
125 Real tol = 1e-11;
126 REL_TEST(MetaPhysicL::raw_value(ad_p), p, tol);
127
128 ADReal ad_T = fp->T_from_v_e(ad_v, ad_e);
129 REL_TEST(MetaPhysicL::raw_value(ad_T), T, tol);
130
131 REL_TEST(MetaPhysicL::raw_value(fp->cv_from_v_e(ad_v, ad_e)), cv, tol);
132
133 ADReal ad_rho = fp->rho_from_p_T(ad_p, ad_T);
134 REL_TEST(MetaPhysicL::raw_value(ad_rho), rho, tol);
135
136 REL_TEST(MetaPhysicL::raw_value(fp->e_from_p_rho(ad_p, ad_rho)), e, tol);
137 REL_TEST(MetaPhysicL::raw_value(fp->e_from_T_v(ad_T, ad_v)), e, tol);
138 REL_TEST(MetaPhysicL::raw_value(fp->e_from_p_T(ad_p, ad_T)), e, tol);
139 REL_TEST(
140 MetaPhysicL::raw_value(fp->gamma_from_v_e(ad_v, ad_e)), fp->gamma_from_v_e(v, e), tol);
141 REL_TEST(MetaPhysicL::raw_value(fp->gamma_from_p_T(ad_p, ad_T)),
142 fp->gamma_from_p_T(ad_p, ad_T),
143 tol);
144 REL_TEST(MetaPhysicL::raw_value(fp->c_from_v_e(ad_v, ad_e)), c, tol);
145 REL_TEST(MetaPhysicL::raw_value(fp->c_from_p_T(ad_p, ad_T)), c, tol);
146 }
147 }
148
149 // check e/h lookups for T = 325.0 & e_from_v_h
150 {
151 Real T = 325.0;
152 Real p = 1.0e6;
153 Real e = 10342290 * 0.75 + 17034360 * 0.25;
154 Real h = e + p / fp->rho_from_p_T(p, T);
155 Real v = fp->v_from_p_T(p, T);
156
157 REL_TEST(h, fp->h_from_p_T(p, T), 1e-5);
158 REL_TEST(e, fp->e_from_p_T(p, T), 1e-5);
159 REL_TEST(e, fp->e_from_v_h(v, h), 1e-5);
160 }
161
162 // check cv/cp lookups for T = 325.0
163 {
164 Real T = 325.0;
165 Real p = 1.0e6;
166 Real cv = (17034360.0 - 10342290.0) / 100.0;
167 Real cp = cv + 8.3144598 / 0.002;
168 REL_TEST(cp, fp->cp_from_p_T(p, T), 1e-5);
169 REL_TEST(cv, fp->cv_from_p_T(p, T), 1e-5);
170
171 Real v = fp->v_from_p_T(p, T);
172 Real e = fp->e_from_p_T(p, T);
173 REL_TEST(cp, fp->cp_from_v_e(v, e), 1e-5);
174 REL_TEST(cv, fp->cv_from_v_e(v, e), 1e-5);
175 }
176
177 // test mu(p, T), mu(v, e), k(p, T), k(v, e) & derivatives
178 {
179 Real T = 250.0;
180 Real p = 1.0e6;
181 REL_TEST(fp->mu_from_p_T(p, T), 2.875, 1e-5);
182 REL_TEST(fp->k_from_p_T(p, T), 7.25, 1e-5);
183
184 Real v = fp->v_from_p_T(p, T);
185 Real e = fp->e_from_p_T(p, T);
186 REL_TEST(fp->mu_from_v_e(v, e), 2.875, 0.001);
187 REL_TEST(fp->k_from_v_e(v, e), 7.25, 0.001);
188
189 Real mu, dmu_dp, dmu_dT;
190 fp->mu_from_p_T(p, T, mu, dmu_dp, dmu_dT);
191 REL_TEST(dmu_dT, 0.0125, 1e-5);
192
193 Real k, dk_dp, dk_dT;
194 fp->k_from_p_T(p, T, k, dk_dp, dk_dT);
195 REL_TEST(dk_dT, -0.025, 1e-5);
196
197 Real cv = fp->cv_from_p_T(p, T);
198 Real dmu_dv, dmu_de;
199 fp->mu_from_v_e(v, e, mu, dmu_dv, dmu_de);
200 REL_TEST(dmu_de, 0.0125 / cv, 0.001);
201
202 Real dk_dv, dk_de;
203 fp->k_from_v_e(v, e, k, dk_dv, dk_de);
204 REL_TEST(dk_de, -0.025 / cv, 0.001);
205 }
206
207 // 5 argument functions
208 {
209 Real T = 325.0;
210 Real p = 1.0e6;
211 Real e = 10342290 * 0.75 + 17034360 * 0.25;
212 Real h = e + p / fp->rho_from_p_T(p, T);
213 Real v = fp->v_from_p_T(p, T);
214 Real rho = 1.0 / v;
215 Real cp = fp->cp_from_p_T(p, T);
216 Real cv = fp->cv_from_p_T(p, T);
217 Real s = fp->s_from_p_T(p, T);
218 Real mu = fp->mu_from_v_e(v, e);
219 Real k = fp->k_from_v_e(v, e);
220 Real gamma = fp->gamma_from_p_T(p, T);
221 Real ssound = fp->c_from_p_T(p, T);
222 Real tol = 1e-12;
223
224 {
225 Real a, b, c;
226 fp->p_from_v_e(v, e, a, b, c);
227 REL_TEST(a, p, tol);
228 DERIV_TEST_CUSTOM_PERTURBATION(fp->p_from_v_e, v, e, 1e-4, 1e-4);
229 }
230
231 {
232 Real a, b, c;
233 fp->T_from_v_e(v, e, a, b, c);
234 REL_TEST(a, T, tol);
235 DERIV_TEST_CUSTOM_PERTURBATION(fp->T_from_v_e, v, e, 1e-4, 1e-4);
236 }
237
238 {
239 Real a, b, c;
240 fp->cp_from_v_e(v, e, a, b, c);
241 REL_TEST(a, cp, tol);
242 DERIV_TEST_CUSTOM_PERTURBATION(fp->cp_from_v_e, v, e, 1e-4, 1e-4);
243 }
244
245 {
246 Real a, b, c;
247 fp->cv_from_v_e(v, e, a, b, c);
248 REL_TEST(a, cv, tol);
249 DERIV_TEST_CUSTOM_PERTURBATION(fp->cv_from_v_e, v, e, 1e-4, 1e-4);
250 }
251
252 {
253 Real a, b, c;
254 fp->mu_from_v_e(v, e, a, b, c);
255 REL_TEST(a, mu, tol);
256 DERIV_TEST_CUSTOM_PERTURBATION(fp->mu_from_v_e, v, e, 1e-4, 1e-4);
257 }
258
259 {
260 Real a, b, c;
261 fp->k_from_v_e(v, e, a, b, c);
262 REL_TEST(a, k, tol);
263 DERIV_TEST_CUSTOM_PERTURBATION(fp->k_from_v_e, v, e, 1e-4, 1e-4);
264 }
265
266 {
267 Real a, b, c;
268 fp->s_from_v_e(v, e, a, b, c);
269 REL_TEST(a, s, tol);
270 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_v_e, v, e, 1e-4, 1e-4);
271 }
272
273 {
274 Real a, b, c;
275 fp->s_from_p_T(p, T, a, b, c);
276 REL_TEST(a, s, tol);
277 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_p_T, p, T, 1e-4, 1e-4);
278 }
279
280 {
281 Real a, b, c;
282 fp->s_from_h_p(h, p, a, b, c);
283 REL_TEST(a, s, tol);
284 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_h_p, h, p, 1e-4, 1e-4);
285 }
286
287 {
288 Real a, b, c;
289 fp->e_from_v_h(v, h, a, b, c);
290 REL_TEST(a, e, tol);
291 DERIV_TEST_CUSTOM_PERTURBATION(fp->e_from_v_h, v, h, 1e-4, 1e-4);
292 }
293
294 {
295 Real a, b, c;
296 fp->rho_from_p_T(p, T, a, b, c);
297 REL_TEST(a, rho, tol);
298 DERIV_TEST_CUSTOM_PERTURBATION(fp->rho_from_p_T, p, T, 1e-4, 1e-4);
299 }
300
301 {
302 Real a, b, c;
303 fp->e_from_p_rho(p, rho, a, b, c);
304 REL_TEST(a, e, tol);
305 DERIV_TEST_CUSTOM_PERTURBATION(fp->e_from_p_rho, p, rho, 1e-4, 1e-4);
306 }
307
308 {
309 Real a, b, c;
310 fp->e_from_T_v(T, v, a, b, c);
311 REL_TEST(a, e, tol);
312 DERIV_TEST_CUSTOM_PERTURBATION(fp->e_from_T_v, T, v, 1e-4, 1e-4);
313 }
314
315 {
316 Real a, b, c;
317 fp->p_from_T_v(T, v, a, b, c);
318 REL_TEST(a, p, tol);
319 DERIV_TEST_CUSTOM_PERTURBATION(fp->p_from_T_v, T, v, 1e-4, 1e-4);
320 }
321
322 {
323 Real a, b, c;
324 fp->h_from_T_v(T, v, a, b, c);
325 REL_TEST(a, h, tol);
326 DERIV_TEST_CUSTOM_PERTURBATION(fp->h_from_T_v, T, v, 1e-4, 1e-4);
327 }
328
329 {
330 Real a, b, c;
331 fp->s_from_T_v(T, v, a, b, c);
332 REL_TEST(a, s, tol);
333 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_T_v, T, v, 1e-4, 1e-4);
334 }
335
336 {
337 Real a, b, c;
338 fp->h_from_p_T(p, T, a, b, c);
339 REL_TEST(a, h, tol);
340 DERIV_TEST_CUSTOM_PERTURBATION(fp->h_from_p_T, p, T, 1e-4, 1e-4);
341 }
342
343 {
344 Real a, b, c;
345 fp->e_from_p_T(p, T, a, b, c);
346 REL_TEST(a, e, tol);
347 DERIV_TEST_CUSTOM_PERTURBATION(fp->e_from_p_T, p, T, 1e-4, 1e-4);
348 }
349
350 {
351 Real a, b, c;
352 fp->T_from_p_h(p, h, a, b, c);
353 REL_TEST(a, T, tol);
354 DERIV_TEST_CUSTOM_PERTURBATION(fp->T_from_p_h, p, h, 1e-4, 1e-4);
355 }
356
357 {
358 Real a, b, c;
359 fp->cv_from_p_T(p, T, a, b, c);
360 REL_TEST(a, cv, tol);
361 DERIV_TEST_CUSTOM_PERTURBATION(fp->cv_from_p_T, p, T, 1e-4, 1e-4);
362 }
363
364 {
365 Real a, b, c;
366 fp->cp_from_p_T(p, T, a, b, c);
367 REL_TEST(a, cp, tol);
368 DERIV_TEST_CUSTOM_PERTURBATION(fp->cp_from_p_T, p, T, 1e-4, 1e-4);
369 }
370
371 {
372 Real a, b, c;
373 fp->mu_from_p_T(p, T, a, b, c);
374 REL_TEST(a, mu, tol);
375 DERIV_TEST_CUSTOM_PERTURBATION(fp->mu_from_p_T, p, T, 1e-4, 1e-4);
376 }
377
378 {
379 Real a, b, c;
380 fp->k_from_p_T(p, T, a, b, c);
381 REL_TEST(a, k, tol);
382 DERIV_TEST_CUSTOM_PERTURBATION(fp->k_from_p_T, p, T, 1e-4, 1e-4);
383 }
384
385 {
386 Real a, b, c;
387 fp->gamma_from_p_T(p, T, a, b, c);
388 REL_TEST(a, gamma, tol);
389 DERIV_TEST_CUSTOM_PERTURBATION(fp->gamma_from_p_T, p, T, 1e-4, 1e-4);
390 }
391
392 {
393 Real a, b, c;
394 fp->gamma_from_v_e(v, e, a, b, c);
395 REL_TEST(a, gamma, tol);
396 DERIV_TEST_CUSTOM_PERTURBATION(fp->gamma_from_v_e, v, e, 1e-4, 1e-4);
397 }
398
399 {
400 Real a, b, c;
401 fp->c_from_v_e(v, e, a, b, c);
402 REL_TEST(a, ssound, tol);
403 DERIV_TEST_CUSTOM_PERTURBATION(fp->c_from_v_e, v, e, 1e-4, 1e-4);
404 }
405
406 {
407 Real a, b, c;
408 fp->c_from_p_T(p, T, a, b, c);
409 REL_TEST(a, ssound, tol);
410 DERIV_TEST_CUSTOM_PERTURBATION(fp->c_from_p_T, p, T, 1e-4, 1e-4);
411 }
412 }
413
414 // test entropy functions
415 {
416 Real T = 489.305;
417 Real Z = 0.5 * (80459 + 80460.7);
418 Real p = 1.0e6;
419 const Real rho = fp->rho_from_p_T(p, T);
420 const Real v = 1.0 / rho;
421 const Real v0 = 1.0;
422 Real e = fp->e_from_p_T(p, T);
423 Real h = fp->h_from_p_T(p, T);
424 Real s = Z + Rs * std::log(v / v0);
425
426 REL_TEST(fp->s_from_p_T(p, T), s, 1e-6);
427 REL_TEST(fp->s_from_v_e(v, e), s, 1e-6);
428 REL_TEST(fp->s_from_h_p(h, p), s, 1e-6);
429 REL_TEST(fp->s_from_T_v(T, v), s, 1e-6);
430
431 // test 5 arg functions with derivatives for s(p, T)
432 {
433 Real s_alt, ds_dp, ds_dT;
434 fp->s_from_p_T(p, T, s_alt, ds_dp, ds_dT);
435 REL_TEST(s_alt, s, 1e-5);
436 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_p_T, p, T, 1e-4, 1e-4);
437 }
438
439 // test 5 arg functions with derivatives for s(e, v)
440 {
441 Real s_alt, ds_dv, ds_de;
442 fp->s_from_v_e(v, e, s_alt, ds_dv, ds_de);
443 REL_TEST(s_alt, s, 1e-5);
444 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_v_e, v, e, 1e-4, 1e-4);
445 }
446
447 // test 5 arg functions with derivatives for s(h, p)
448 {
449 Real s_alt, ds_dh, ds_dp;
450 fp->s_from_h_p(h, p, s_alt, ds_dh, ds_dp);
451 REL_TEST(s_alt, s, 1e-5);
452 DERIV_TEST_CUSTOM_PERTURBATION(fp->s_from_h_p, h, p, 1e-4, 1e-4);
453 }
454 }
455
456 // test out of bounds call for temperature
457 {
458 try
459 {
460 fp->cp_from_p_T(1.0e6, 600.0);
461 FAIL();
462 }
463 catch (const std::exception & err)
464 {
465 std::size_t pos = std::string(err.what()).find("which is outside of the bounds of");
466 ASSERT_TRUE(pos != std::string::npos);
467 }
468
469 try
470 {
471 fp->cp_from_p_T(1.0e6, 99.0);
472 FAIL();
473 }
474 catch (const std::exception & err)
475 {
476 std::size_t pos = std::string(err.what()).find("which is outside of the bounds of");
477 ASSERT_TRUE(pos != std::string::npos);
478 }
479 }
480}
DualNumber< Real, DNDerivativeType, true > ADReal
const double tol
auto raw_value(const Eigen::Map< T > &in)