Skip to content

Commit 52b3722

Browse files
authored
Fix failing transport property cases (nasa#37)
Fix transport-property failures and legacy-behavior mismatches in CH4/O2 equilibrium/rocket cases, including an out-of-bounds crash path and interval-selection differences.
1 parent c9afe57 commit 52b3722

File tree

7 files changed

+747
-172
lines changed

7 files changed

+747
-172
lines changed

source/equilibrium.f90

Lines changed: 436 additions & 109 deletions
Large diffs are not rendered by default.

source/equilibrium_test.pf

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,20 @@ module equilibrium_test
22
use funit
33
use cea_equilibrium
44
use cea_thermo
5+
use cea_transport
56
use cea_mixture
67
use cea_units
78
use cea_param, only: R=>gas_constant
89

910
type(ThermoDB) :: all_thermo
11+
type(TransportDB) :: all_transport
1012

1113
contains
1214

1315
@before
1416
subroutine setup_mixture()
1517
all_thermo = read_thermo('data/thermo.lib')
18+
all_transport = read_transport('data/trans.lib')
1619
end subroutine
1720

1821
@test
@@ -659,6 +662,36 @@ contains
659662

660663
end subroutine
661664

665+
@test
666+
subroutine test_equilibrium_transport_ch4_o2
667+
type(Mixture) :: products
668+
type(Mixture) :: reactants
669+
type(EqSolver) :: solver
670+
type(EqSolution) :: solution
671+
character(:), allocatable :: product_names(:)
672+
real(dp) :: h_reac, p_reac, weights(2)
673+
674+
reactants = Mixture(all_thermo, ['CH4', 'O2 '])
675+
product_names = reactants%get_products(all_thermo)
676+
products = Mixture(all_thermo, product_names)
677+
678+
solver = EqSolver(products, reactants, all_transport=all_transport)
679+
solution = EqSolution(solver)
680+
681+
weights = reactants%weights_from_of([0.0d0, 1.0d0], [1.0d0, 0.0d0], 2.6d0)
682+
h_reac = reactants%calc_enthalpy(weights, [298.15d0, 298.15d0])/R
683+
p_reac = psi_to_bar(1000.0d0)
684+
685+
call solver%solve(solution, 'hp', h_reac, p_reac, weights)
686+
687+
@assertTrue(solution%converged)
688+
@assertTrue(solution%viscosity > 0.0d0)
689+
@assertTrue(solution%conductivity_fr > 0.0d0)
690+
@assertTrue(solution%conductivity_eq > 0.0d0)
691+
@assertTrue(solution%pr_fr > 0.0d0)
692+
@assertTrue(solution%pr_eq > 0.0d0)
693+
end subroutine
694+
662695
! @test
663696
! subroutine test_inert_reactant
664697
! type(Mixture) :: products
@@ -708,4 +741,4 @@ contains
708741

709742
! end subroutine
710743

711-
end module
744+
end module

source/rocket_test.pf

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,20 @@ module rocket_test
33
use cea_rocket
44
use cea_equilibrium
55
use cea_thermo
6+
use cea_transport
67
use cea_mixture
78
use cea_units
89
use cea_param, only: R=>gas_constant, snl=>species_name_len
910

1011
type(ThermoDB) :: all_thermo
12+
type(TransportDB) :: all_transport
1113

1214
contains
1315

1416
@before
1517
subroutine setup_mixture()
1618
all_thermo = read_thermo('data/thermo.lib')
19+
all_transport = read_transport('data/trans.lib')
1720
end subroutine
1821

1922
@test
@@ -448,4 +451,62 @@ contains
448451

449452
end subroutine
450453

454+
@test
455+
subroutine test_rocket_transport
456+
type(Mixture) :: products
457+
type(Mixture) :: reactants
458+
type(RocketSolver) :: solver
459+
type(RocketSolution) :: soln
460+
character(:), allocatable :: product_names(:)
461+
real(dp) :: hc, pc, weights(2)
462+
real(dp), parameter :: tol = 1.0d-3
463+
464+
reactants = Mixture(all_thermo, ['CH4', 'O2 '])
465+
product_names = reactants%get_products(all_thermo)
466+
products = Mixture(all_thermo, product_names)
467+
468+
weights = reactants%weights_from_of([0.0d0, 1.0d0], [1.0d0, 0.0d0], 2.6d0)
469+
hc = reactants%calc_enthalpy(weights, [298.15d0, 298.15d0])/R
470+
pc = psi_to_bar(1000.0d0)
471+
472+
solver = RocketSolver(products, reactants, all_transport=all_transport)
473+
soln = solver%solve(weights, pc, pi_p=[10.0d0], supar=[20.0d0], hc=hc)
474+
475+
! Test convergence
476+
@assertEqual(.true., soln%converged)
477+
478+
! Chamber transport properties
479+
@assertRelativelyEqual(3371.84d0, soln%eq_soln(1)%T, tol)
480+
@assertRelativelyEqual(1.0391d0, soln%eq_soln(1)%viscosity, tol)
481+
@assertRelativelyEqual(10.4826d0, soln%eq_soln(1)%conductivity_eq, tol)
482+
@assertRelativelyEqual(0.4635d0, soln%eq_soln(1)%pr_eq, tol)
483+
@assertRelativelyEqual(4.1984d0, soln%eq_soln(1)%conductivity_fr, tol)
484+
@assertRelativelyEqual(0.6279d0, soln%eq_soln(1)%pr_fr, tol)
485+
486+
! Throat transport properties
487+
@assertRelativelyEqual(3148.65d0, soln%eq_soln(2)%T, tol)
488+
@assertRelativelyEqual(0.98981d0, soln%eq_soln(2)%viscosity, tol)
489+
@assertRelativelyEqual(8.7103d0, soln%eq_soln(2)%conductivity_eq, tol)
490+
@assertRelativelyEqual(0.4693d0, soln%eq_soln(2)%pr_eq, tol)
491+
@assertRelativelyEqual(3.9367d0, soln%eq_soln(2)%conductivity_fr, tol)
492+
@assertRelativelyEqual(0.6324d0, soln%eq_soln(2)%pr_fr, tol)
493+
494+
! Exit transport properties (pi_p=10, Ae/At=2.3019)
495+
@assertRelativelyEqual(2457.73d0, soln%eq_soln(3)%T, tol)
496+
@assertRelativelyEqual(0.82957d0, soln%eq_soln(3)%viscosity, tol)
497+
@assertRelativelyEqual(4.2652d0, soln%eq_soln(3)%conductivity_eq, tol)
498+
@assertRelativelyEqual(0.5445d0, soln%eq_soln(3)%pr_eq, tol)
499+
@assertRelativelyEqual(3.1312d0, soln%eq_soln(3)%conductivity_fr, tol)
500+
@assertRelativelyEqual(0.6423d0, soln%eq_soln(3)%pr_fr, tol)
501+
502+
! Exit transport properties (supar=20, Ae/At=20)
503+
@assertRelativelyEqual(1442.09d0, soln%eq_soln(4)%T, tol)
504+
@assertRelativelyEqual(0.56764d0, soln%eq_soln(4)%viscosity, tol)
505+
@assertRelativelyEqual(2.0853d0, soln%eq_soln(4)%conductivity_eq, tol)
506+
@assertRelativelyEqual(0.6351d0, soln%eq_soln(4)%pr_eq, tol)
507+
@assertRelativelyEqual(1.9610d0, soln%eq_soln(4)%conductivity_fr, tol)
508+
@assertRelativelyEqual(0.6315d0, soln%eq_soln(4)%pr_fr, tol)
509+
510+
end subroutine
511+
451512
end module

source/transport.f90

Lines changed: 72 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,16 @@ module cea_transport
1515
! Required items
1616
character(16) :: name
1717
!! Species name
18-
integer :: num_intervals
19-
!! Number of temperature intervals
18+
integer :: num_eta_intervals
19+
!! Number of temperature intervals for viscosity
20+
integer :: num_lambda_intervals
21+
!! Number of temperature intervals for thermal conductivity
2022

2123
! Coefficients
22-
! NOTE: This assumes temperature intervals are the same for eta and lambda, which should be true
23-
real(dp), allocatable :: T_fit(:, :)
24-
!! Temperature intervals
24+
real(dp), allocatable :: eta_T_fit(:, :)
25+
!! Temperature intervals for viscosity fit
26+
real(dp), allocatable :: lambda_T_fit(:, :)
27+
!! Temperature intervals for thermal conductivity fit
2528
type(TransportFit), allocatable :: eta_coef(:)
2629
!! Viscosity curve fit coefficients
2730
type(TransportFit), allocatable :: lambda_coef(:)
@@ -83,10 +86,15 @@ elemental function st_calc_eta(self, T) result(eta)
8386
real(dp) :: eta
8487
integer :: i, idx
8588

89+
if (self%num_eta_intervals <= 0) then
90+
eta = 0.0d0
91+
return
92+
end if
93+
8694
! Select temperature range
8795
idx = 1
88-
do i = 1,self%num_intervals
89-
if (T > self%T_fit(i, 1)) then
96+
do i = 2, self%num_eta_intervals
97+
if (self%eta_T_fit(i, 2) > 0.0d0 .and. T > self%eta_T_fit(i-1, 2)) then
9098
idx = i
9199
end if
92100
end do
@@ -101,10 +109,15 @@ elemental function st_calc_lambda(self, T) result(lambda)
101109
real(dp) :: lambda
102110
integer :: i, idx
103111

112+
if (self%num_lambda_intervals <= 0) then
113+
lambda = 0.0d0
114+
return
115+
end if
116+
104117
! Select temperature range
105118
idx = 1
106-
do i = 1,self%num_intervals
107-
if (T > self%T_fit(i, 1)) then
119+
do i = 2, self%num_lambda_intervals
120+
if (self%lambda_T_fit(i, 2) > 0.0d0 .and. T > self%lambda_T_fit(i-1, 2)) then
108121
idx = i
109122
end if
110123
end do
@@ -119,10 +132,15 @@ elemental function bt_calc_eta(self, T) result(eta)
119132
real(dp) :: eta
120133
integer :: i, idx
121134

135+
if (self%num_intervals <= 0) then
136+
eta = 0.0d0
137+
return
138+
end if
139+
122140
! Select temperature range
123141
idx = 1
124-
do i = 1,self%num_intervals
125-
if (T > self%T_fit(i, 1)) then
142+
do i = 2, self%num_intervals
143+
if (self%T_fit(i, 2) > 0.0d0 .and. T > self%T_fit(i-1, 2)) then
126144
idx = i
127145
end if
128146
end do
@@ -145,7 +163,8 @@ function read_transport(filename) result(db)
145163
integer :: i, j ! Index
146164
character(16) :: species(2) ! Species names
147165
real(dp) :: tr_data(6, 3, 2) ! Transport data
148-
integer :: n_int ! Temporary variable for number of intervals
166+
integer :: n_int_eta ! Number of viscosity intervals
167+
integer :: n_int_lambda ! Number of conductivity intervals
149168

150169

151170
call log_info('Reading transport database file: '//filename)
@@ -172,39 +191,39 @@ function read_transport(filename) result(db)
172191
db%pure_species(db%num_pure) = species(1)
173192

174193
! Oversize the curvefit arrays
175-
allocate(db%pure_transport(db%num_pure)%T_fit(3, 2), &
194+
allocate(db%pure_transport(db%num_pure)%eta_T_fit(3, 2), &
195+
db%pure_transport(db%num_pure)%lambda_T_fit(3, 2), &
176196
db%pure_transport(db%num_pure)%eta_coef(3), &
177197
db%pure_transport(db%num_pure)%lambda_coef(3))
178198

179199
db%pure_transport(db%num_pure)%name = species(1)
180200

181201
! Get the number of valid intervals for these coefficients
182-
n_int = 3
183-
do j = 1,3
184-
if (abs(tr_data(1, j, 1)) < 1.0d-6) then
185-
n_int = j-1
186-
exit
187-
end if
188-
end do
189-
db%pure_transport(db%num_pure)%num_intervals = n_int
202+
n_int_eta = count_transport_intervals(tr_data(:,:,1))
203+
n_int_lambda = count_transport_intervals(tr_data(:,:,2))
204+
db%pure_transport(db%num_pure)%num_eta_intervals = n_int_eta
205+
db%pure_transport(db%num_pure)%num_lambda_intervals = n_int_lambda
190206

191207
! Set the coefficients
192-
do j = 1, n_int
193-
db%pure_transport(db%num_pure)%T_fit(j, :) = tr_data(:2, j, 1)
194-
208+
do j = 1, n_int_eta
209+
db%pure_transport(db%num_pure)%eta_T_fit(j, :) = tr_data(:2, j, 1)
195210
db%pure_transport(db%num_pure)%eta_coef(j)%A = tr_data(3, j, 1)
196211
db%pure_transport(db%num_pure)%eta_coef(j)%B = tr_data(4, j, 1)
197212
db%pure_transport(db%num_pure)%eta_coef(j)%C = tr_data(5, j, 1)
198213
db%pure_transport(db%num_pure)%eta_coef(j)%D = tr_data(6, j, 1)
214+
end do
215+
do j = 1, n_int_lambda
216+
db%pure_transport(db%num_pure)%lambda_T_fit(j, :) = tr_data(:2, j, 2)
199217

200218
db%pure_transport(db%num_pure)%lambda_coef(j)%A = tr_data(3, j, 2)
201219
db%pure_transport(db%num_pure)%lambda_coef(j)%B = tr_data(4, j, 2)
202220
db%pure_transport(db%num_pure)%lambda_coef(j)%C = tr_data(5, j, 2)
203221
db%pure_transport(db%num_pure)%lambda_coef(j)%D = tr_data(6, j, 2)
204222
end do
205-
db%pure_transport(db%num_pure)%T_fit = db%pure_transport(db%num_pure)%T_fit(:n_int, :)
206-
db%pure_transport(db%num_pure)%eta_coef = db%pure_transport(db%num_pure)%eta_coef(:n_int)
207-
db%pure_transport(db%num_pure)%lambda_coef = db%pure_transport(db%num_pure)%lambda_coef(:n_int)
223+
db%pure_transport(db%num_pure)%eta_T_fit = db%pure_transport(db%num_pure)%eta_T_fit(:n_int_eta, :)
224+
db%pure_transport(db%num_pure)%lambda_T_fit = db%pure_transport(db%num_pure)%lambda_T_fit(:n_int_lambda, :)
225+
db%pure_transport(db%num_pure)%eta_coef = db%pure_transport(db%num_pure)%eta_coef(:n_int_eta)
226+
db%pure_transport(db%num_pure)%lambda_coef = db%pure_transport(db%num_pure)%lambda_coef(:n_int_lambda)
208227

209228
else
210229
! Binary species
@@ -218,26 +237,20 @@ function read_transport(filename) result(db)
218237
db%binary_transport(db%num_binary)%name = species
219238

220239
! Get the number of valid intervals for these coefficients
221-
n_int = 3
222-
do j = 1,3
223-
if (abs(tr_data(1, j, 1)) < 1.0d-6) then
224-
n_int = j-1
225-
exit
226-
end if
227-
end do
228-
db%binary_transport(db%num_binary)%num_intervals = n_int
240+
n_int_eta = count_transport_intervals(tr_data(:,:,1))
241+
db%binary_transport(db%num_binary)%num_intervals = n_int_eta
229242

230243
! Set the coefficients
231-
do j = 1, n_int
244+
do j = 1, n_int_eta
232245
db%binary_transport(db%num_binary)%T_fit(j, :) = tr_data(:2, j, 1)
233246

234247
db%binary_transport(db%num_binary)%eta_coef(j)%A = tr_data(3, j, 1)
235248
db%binary_transport(db%num_binary)%eta_coef(j)%B = tr_data(4, j, 1)
236249
db%binary_transport(db%num_binary)%eta_coef(j)%C = tr_data(5, j, 1)
237250
db%binary_transport(db%num_binary)%eta_coef(j)%D = tr_data(6, j, 1)
238251
end do
239-
db%binary_transport(db%num_binary)%T_fit = db%binary_transport(db%num_binary)%T_fit(:n_int, :)
240-
db%binary_transport(db%num_binary)%eta_coef = db%binary_transport(db%num_binary)%eta_coef(:n_int)
252+
db%binary_transport(db%num_binary)%T_fit = db%binary_transport(db%num_binary)%T_fit(:n_int_eta, :)
253+
db%binary_transport(db%num_binary)%eta_coef = db%binary_transport(db%num_binary)%eta_coef(:n_int_eta)
241254

242255
end if
243256

@@ -252,6 +265,27 @@ function read_transport(filename) result(db)
252265

253266
end function
254267

268+
integer function count_transport_intervals(visc_tfit, cond_tfit) result(n_int)
269+
real(dp), intent(in) :: visc_tfit(6,3)
270+
real(dp), intent(in), optional :: cond_tfit(6,3)
271+
integer :: j
272+
273+
n_int = 0
274+
do j = 1, 3
275+
if (visc_tfit(2, j) > 0.0d0) then
276+
n_int = j
277+
cycle
278+
end if
279+
if (present(cond_tfit)) then
280+
if (cond_tfit(2, j) > 0.0d0) then
281+
n_int = j
282+
cycle
283+
end if
284+
end if
285+
exit
286+
end do
287+
end function
288+
255289
function get_mixture_transport(all_transport, products, ions) result(transport_db)
256290
! Get the transport database for the subset of species in the mixture
257291
type(TransportDB), intent(in) :: all_transport

0 commit comments

Comments
 (0)