Skip to content

Commit 6d6cc56

Browse files
authored
fixed minor fac rocket divergence (#54)
* fixed minor fac rocket divergence
1 parent 4c1cb82 commit 6d6cc56

4 files changed

Lines changed: 124 additions & 113 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ All notable user-visible changes to this project are documented here.
88
- Python `Mixture` input validation now accepts `str` and `cea.Reactant` entries (including mixed lists) and no longer accepts raw `bytes` species names (`#53`).
99
- Added SI-focused custom-reactant handling at the Python API layer: `Reactant.temperature` is specified in K and `Reactant.enthalpy` in J/kg (converted internally for core input) (`#53`).
1010
- Legacy input parsing now supports repeated `outp` dataset keywords (including multiline forms) by merging successive `outp` entries during dataset assembly (`#52`).
11+
- FAC rocket chamber-closure iteration logic in `RocketSolver_solve_fac` was updated toward CEA2 parity: Option-1 pressure correction direction now follows legacy semantics, the Option-1 convergence check is normalized to assigned injector pressure, the fixed 4-pass outer loop was replaced with tolerance-driven iteration plus a bounded safety guard, and FAC combustor-end reseeding now refreshes from the current infinity state each chamber iteration (`#54`).
1112

1213
### Fixed
1314
- Legacy CLI equilibrium/rocket/shock workflows now propagate `include_ions` into generated product mixtures so ionized products are retained when requested (`#52`).

source/bind/python/tests/test_rp1311_samples.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,10 +362,10 @@ def test_example9_fac_rocket(cea_module):
362362
solver.solve(soln, w, pc, pi_p, supar=supar, ac_at=1.58, iac=False, hc=hc)
363363

364364
assert soln.num_pts == 10
365-
assert soln.T[0] == pytest.approx(3383.844614137881, rel=1e-5)
366-
assert soln.c_star[0] == pytest.approx(2330.967589918211, rel=1e-5)
367-
assert soln.Isp_vacuum[-1] == pytest.approx(4554.315454546227, rel=1e-5)
368-
assert soln.coefficient_of_thrust[-1] == pytest.approx(1.8869095701543406, rel=1e-5)
365+
assert soln.T[0] == pytest.approx(3383.84, rel=1e-4)
366+
assert soln.c_star[0] == pytest.approx(2331.0, rel=1e-4)
367+
assert soln.Isp_vacuum[-1] == pytest.approx(4554.3, rel=1e-4)
368+
assert soln.coefficient_of_thrust[-1] == pytest.approx(1.8869, rel=1e-4)
369369

370370

371371
@pytest.mark.rp1311

source/rocket.f90

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -975,6 +975,7 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
975975
integer :: n_frz_ ! Temporary variable for frozen index
976976
integer :: num_pts ! Total number of evaluation points
977977
integer, parameter :: max_iter_area = 10 ! Maximum number of iterations for exit condition using area ratio
978+
integer, parameter :: max_iter_chamber = 100 ! Safety guard for FAC chamber-closure iterations
978979
real(dp), parameter :: area_tol = 4.0d-5 ! Area-ratio convergence tolerance
979980
character(len=2) :: prob_type ! Equilibrium problem type
980981
real(dp) :: state1 ! Chamber temperature or enthalpy, or entropy at other stations
@@ -994,6 +995,7 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
994995
real(dp) :: volume ! Volume temporary variable
995996
logical :: use_acat ! Flag to use the contraction ratio for chamber solution (if false, use mdot)
996997
logical :: frozen ! Flag to determine if frozen is used
998+
integer :: chamber_iter ! FAC chamber-closure iteration counter
997999
real(dp) :: acatsv, pratsv, mat, prat, pjrat, pr, pracat
9981000

9991001
! Index of solution:
@@ -1093,8 +1095,10 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
10931095
! P_c initial guess
10941096
soln%pressure(3) = p_inf
10951097

1096-
! Iterate until combustor conditions converge
1097-
do i = 1, 4 ! Max outer iterations
1098+
! Iterate until combustor conditions converge (legacy CEA2-style stopping test).
1099+
chamber_iter = 0
1100+
do
1101+
chamber_iter = chamber_iter + 1
10981102

10991103
soln%pressure(2) = p_inf
11001104

@@ -1119,21 +1123,17 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
11191123
! -----------------------------------------------
11201124
idx = 3
11211125

1122-
! Update initial guess of Pc
1123-
if (i == 1) then
1124-
! Set equilibrium initial guess
1125-
soln%eq_soln(idx) = EqSolution(self%eq_solver, T_init=soln%eq_soln(1)%T, nj_init=soln%eq_soln(1)%nj)
1126-
1127-
ln_pinf_pt = log(soln%pressure(2)/soln%pressure(4))
1128-
ln_pinf_pc = ln_pinf_pt/(ac_at_ + 10.587d0*(log(ac_at_)**3.0d0) + 9.454d0*log(ac_at_))
1129-
if (ac_at_ < 1.09d0) then
1130-
ln_pinf_pc = 0.9d0*ln_pinf_pc
1131-
else if (ac_at_ > 10.0d0) then
1132-
ln_pinf_pc = ln_pinf_pc/ac_at_
1133-
end if
1134-
! Update the pressure
1135-
soln%pressure(idx) = p_inf/exp(ln_pinf_pc)
1126+
! Re-seed combustor-end iterate from the current infinity state
1127+
soln%eq_soln(idx) = EqSolution(self%eq_solver, T_init=soln%eq_soln(2)%T, nj_init=soln%eq_soln(2)%nj)
1128+
ln_pinf_pt = log(soln%pressure(2)/soln%pressure(4))
1129+
ln_pinf_pc = ln_pinf_pt/(ac_at_ + 10.587d0*(log(ac_at_)**3.0d0) + 9.454d0*log(ac_at_))
1130+
if (ac_at_ < 1.09d0) then
1131+
ln_pinf_pc = 0.9d0*ln_pinf_pc
1132+
else if (ac_at_ > 10.0d0) then
1133+
ln_pinf_pc = ln_pinf_pc/ac_at_
11361134
end if
1135+
! Update the pressure
1136+
soln%pressure(idx) = p_inf/exp(ln_pinf_pc)
11371137

11381138
! -----------------------------------------------
11391139
! Iterate at the combustor end until convergence for assigned area ratio
@@ -1175,10 +1175,12 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
11751175

11761176
if (use_acat) then
11771177

1178-
prat = (p_inj_check/pc)
1178+
prat = pc/p_inj_check
11791179

11801180
! Check combustor convergence (Eq. 6.29)
1181-
if (abs(pc - p_inj_check)/p_inj_check <= c_tol) exit
1181+
if (abs(pc - p_inj_check)/pc <= c_tol) then
1182+
exit
1183+
end if
11821184

11831185
! Update estimate
11841186
p_inf = p_inf*prat
@@ -1191,7 +1193,9 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
11911193
prat = (1.0257d0 - 1.2318d0*ac_at_)/(1.0d0 - 1.26505d0*ac_at_)
11921194

11931195
! Check combustor convergence (Eq. 6.29)
1194-
if (abs(pc - p_inj_check)/p_inj_check <= c_tol) exit
1196+
if (abs(pc - p_inj_check)/p_inj_check <= c_tol) then
1197+
exit
1198+
end if
11951199

11961200
pjrat = p_inj_check/pc
11971201
do k = 1, 2
@@ -1206,6 +1210,12 @@ subroutine RocketSolver_solve_fac(self, soln, reactant_weights, pc, pi_p, subar,
12061210
end do
12071211
end if
12081212

1213+
if (chamber_iter >= max_iter_chamber) then
1214+
call log_warning('RocketSolver FAC: chamber conditions did not converge within '// &
1215+
to_str(max_iter_chamber)//' iterations; continuing with last iterate')
1216+
exit
1217+
end if
1218+
12091219
end do
12101220

12111221
! Recompute throat under frozen assumptions after chamber convergence,

0 commit comments

Comments
 (0)