@@ -145,6 +145,71 @@ subroutine ShockSolver_update_solution(self, soln, X1, X2, p21, t21, iter)
145145
146146 end subroutine
147147
148+ logical function ShockSolver_state_valid (soln , idx ) result(valid)
149+ type (ShockSolution), intent (in ) :: soln
150+ integer , intent (in ) :: idx
151+
152+ valid = .false.
153+ if (idx < 1 .or. idx > soln% num_pts) return
154+
155+ valid = soln% eq_soln(idx)% converged .and. &
156+ soln% eq_soln(idx)% T > 0.0d0 .and. &
157+ soln% eq_soln(idx)% n > 0.0d0
158+ end function
159+
160+ subroutine ShockSolver_fail_state (soln , idx , message )
161+ type (ShockSolution), intent (inout ) :: soln
162+ integer , intent (in ) :: idx
163+ character (* ), intent (in ) :: message
164+
165+ if (len_trim (message) > 0 ) call log_warning(trim (message))
166+ call log_warning(" Shock calculation stopped after the last valid point." )
167+
168+ soln% converged = .false.
169+ soln% pressure(idx) = 0.0d0
170+ soln% mach(idx) = 0.0d0
171+ soln% u(idx) = 0.0d0
172+ soln% v_sonic(idx) = 0.0d0
173+ soln% eq_soln(idx)% T = 0.0d0
174+ soln% eq_soln(idx)% n = 0.0d0
175+ soln% eq_soln(idx)% converged = .false.
176+ soln% eq_partials(idx)% dlnV_dlnP = 0.0d0
177+ soln% eq_partials(idx)% dlnV_dlnT = 0.0d0
178+ soln% eq_partials(idx)% gamma_s = 0.0d0
179+
180+ select case (idx)
181+ case (2 )
182+ soln% rho12 = 0.0d0
183+ soln% p21 = 0.0d0
184+ soln% t21 = 0.0d0
185+ soln% M21 = 0.0d0
186+ soln% v2 = 0.0d0
187+ if (soln% num_pts >= 3 ) then
188+ soln% pressure(3 ) = 0.0d0
189+ soln% mach(3 ) = 0.0d0
190+ soln% u(3 ) = 0.0d0
191+ soln% v_sonic(3 ) = 0.0d0
192+ soln% eq_soln(3 )% T = 0.0d0
193+ soln% eq_soln(3 )% n = 0.0d0
194+ soln% eq_soln(3 )% converged = .false.
195+ soln% eq_partials(3 )% dlnV_dlnP = 0.0d0
196+ soln% eq_partials(3 )% dlnV_dlnT = 0.0d0
197+ soln% eq_partials(3 )% gamma_s = 0.0d0
198+ soln% rho52 = 0.0d0
199+ soln% p52 = 0.0d0
200+ soln% t52 = 0.0d0
201+ soln% M52 = 0.0d0
202+ soln% u5_p_v2 = 0.0d0
203+ end if
204+ case (3 )
205+ soln% rho52 = 0.0d0
206+ soln% p52 = 0.0d0
207+ soln% t52 = 0.0d0
208+ soln% M52 = 0.0d0
209+ soln% u5_p_v2 = 0.0d0
210+ end select
211+ end subroutine
212+
148213 subroutine ShockSolver_solve_incident (self , soln , weights , T0 , P0 )
149214 ! Solve the incident shock conditions
150215
@@ -198,6 +263,11 @@ subroutine ShockSolver_solve_incident(self, soln, weights, T0, P0)
198263
199264 soln% pressure(idx) = p21* P0
200265 call self% eq_solver% solve(soln% eq_soln(idx), " hp" , h0, soln% pressure(idx), weights, partials= soln% eq_partials(idx))
266+ if (.not. ShockSolver_state_valid(soln, idx)) then
267+ call ShockSolver_fail_state(soln, idx, &
268+ " ShockSolver_solve_incident: incident equilibrium initialization failed." )
269+ return
270+ end if
201271
202272 t21 = soln% eq_soln(idx)% T/ T0
203273 ttmax = 1.05 * T_gas_max/ T0
@@ -209,6 +279,11 @@ subroutine ShockSolver_solve_incident(self, soln, weights, T0, P0)
209279 T2 = t21* T0
210280
211281 call self% eq_solver% solve(soln% eq_soln(idx), " tp" , T2, soln% pressure(idx), weights, partials= soln% eq_partials(idx))
282+ if (.not. ShockSolver_state_valid(soln, idx)) then
283+ call ShockSolver_fail_state(soln, idx, &
284+ " ShockSolver_solve_incident: incident equilibrium iteration failed." )
285+ return
286+ end if
212287
213288 ! Update properties after the equilibrium shock
214289 wm_k = 1.0d0 / soln% eq_soln(idx)% n
@@ -244,10 +319,8 @@ subroutine ShockSolver_solve_incident(self, soln, weights, T0, P0)
244319 call self% update_solution(soln, X(1 ), X(2 ), p21, t21, i)
245320
246321 if (i == 1 .and. .not. soln% converged .and. t21 >= ttmax) then
247- call log_warning(" ShockSolver_solve_incident: first-iteration update hit " // &
248- " temperature cap; marking incident point as failed." )
249- soln% eq_soln(idx)% T = 0.0d0
250- soln% pressure(idx) = 0.0d0
322+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_incident: first-iteration update hit " // &
323+ " temperature cap; marking incident point as failed." )
251324 return
252325 end if
253326
@@ -268,14 +341,7 @@ subroutine ShockSolver_solve_incident(self, soln, weights, T0, P0)
268341
269342 ! Not converged; compute shock properties
270343 if (.not. soln% converged) then
271- soln% rho12 = rho12
272- soln% p21 = p21
273- soln% t21 = t21
274- soln% u(idx) = u1* rho12
275- soln% M21 = wm_k/ wm
276- soln% mach(idx) = soln% M21* mach1
277- soln% v_sonic(idx) = (R* T2* (cp/ (cp - 1.0 / wm_k))/ wm_k)** 0.5d0
278- soln% v2 = u1 - soln% u(idx)
344+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_incident: incident equilibrium solve did not converge." )
279345 end if
280346
281347 end subroutine
@@ -394,10 +460,8 @@ subroutine ShockSolver_solve_incident_frozen(self, soln, weights, T0, P0)
394460 call self% update_solution(soln, X(1 ), X(2 ), p21, t21, i)
395461
396462 if (i == 1 .and. .not. soln% converged .and. t21 >= ttmax) then
397- call log_warning(" ShockSolver_solve_incident_frozen: first-iteration update hit " // &
398- " temperature cap; marking incident point as failed." )
399- soln% eq_soln(idx)% T = 0.0d0
400- soln% pressure(idx) = 0.0d0
463+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_incident_frozen: first-iteration update hit " // &
464+ " temperature cap; marking incident point as failed." )
401465 return
402466 end if
403467
@@ -419,14 +483,7 @@ subroutine ShockSolver_solve_incident_frozen(self, soln, weights, T0, P0)
419483
420484 ! Not converged; compute shock properties
421485 if (.not. soln% converged) then
422- soln% rho12 = rho12
423- soln% p21 = p21
424- soln% t21 = t21
425- soln% u(idx) = u1* rho12
426- soln% M21 = wm_k/ wm
427- soln% mach(idx) = soln% M21* mach1
428- soln% v_sonic(idx) = (R* T2* (cp/ (cp - 1.0 / wm_k))/ wm_k)** 0.5d0
429- soln% v2 = u1 - soln% u(idx)
486+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_incident_frozen: incident frozen solve did not converge." )
430487 end if
431488
432489 end subroutine
@@ -456,7 +513,7 @@ subroutine ShockSolver_solve_reflected(self, soln, weights, T0, P0)
456513 real (dp) :: G(2 , 3 ) ! Solution matrix
457514 real (dp) :: X(3 ) ! Solution vector
458515 real (dp) :: dlnV_dlnP, dlnV_dlnT ! Partial derivatives
459- real (dp) :: rho12 ! Ratios of chemical potential and density across the incident shock
516+ real (dp) :: rho12 ! Incident-shock density ratio carried into reflected solve
460517 real (dp) :: mu25rt, rho52 ! Ratios of chemical potential and density across the reflected shock
461518 real (dp) :: tmp ! Intermediate variabls
462519 real (dp), allocatable :: nj_g(:) ! Total/gas species concentrations [kmol-per-kg]
@@ -492,6 +549,11 @@ subroutine ShockSolver_solve_reflected(self, soln, weights, T0, P0)
492549 T5 = t52* T2
493550
494551 call self% eq_solver% solve(soln% eq_soln(idx), " tp" , T5, soln% pressure(idx), weights, partials= soln% eq_partials(idx))
552+ if (.not. ShockSolver_state_valid(soln, idx)) then
553+ call ShockSolver_fail_state(soln, idx, &
554+ " ShockSolver_solve_reflected: reflected equilibrium iteration failed." )
555+ return
556+ end if
495557
496558 ! Update properties after the equilibrium shock
497559 wm_k = 1.0d0 / soln% eq_soln(idx)% n
@@ -531,10 +593,8 @@ subroutine ShockSolver_solve_reflected(self, soln, weights, T0, P0)
531593 call self% update_solution(soln, X(1 ), X(2 ), p52, t52, i)
532594
533595 if (i == 1 .and. .not. soln% converged .and. t52 >= ttmax) then
534- call log_warning(" ShockSolver_solve_reflected: first-iteration update hit " // &
535- " temperature cap; marking reflected point as failed." )
536- soln% eq_soln(idx)% T = 0.0d0
537- soln% pressure(idx) = 0.0d0
596+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_reflected: first-iteration update hit " // &
597+ " temperature cap; marking reflected point as failed." )
538598 return
539599 end if
540600
@@ -555,14 +615,7 @@ subroutine ShockSolver_solve_reflected(self, soln, weights, T0, P0)
555615
556616 ! Not converged; compute shock properties
557617 if (.not. soln% converged) then
558- soln% rho52 = rho52
559- soln% p52 = p52
560- soln% t52 = t52
561- soln% u(idx) = (u1 - u1* rho12)/ rho52
562- soln% M52 = wm_k/ wm
563- soln% mach(idx) = soln% M52* soln% mach(2 )
564- soln% u5_p_v2 = (u1 - u1* rho12)* (1.0d0-1.0d0 / rho52)
565- soln% v_sonic(idx) = (R* T5* (cp/ (cp - 1.0 / wm_k))/ wm_k)** 0.5d0
618+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_reflected: reflected equilibrium solve did not converge." )
566619 end if
567620
568621 end subroutine
@@ -594,6 +647,7 @@ subroutine ShockSolver_solve_reflected_frozen(self, soln, weights, T0, P0)
594647 real (dp) :: dlnV_dlnP, dlnV_dlnT ! Partial derivatives
595648 real (dp) :: rho12 ! Ratios of chemical potential and density across the incident shock
596649 real (dp) :: mu25rt, rho52 ! Ratios of chemical potential and density across the reflected shock
650+ real (dp) :: rho25_inv ! Reflected-shock inverse density ratio used in the Newton system
597651 real (dp) :: tmp ! Intermediate variabls
598652 integer , parameter :: max_iter = 60
599653 real (dp), parameter :: T_gas_max = 20000.d0 ! Max gas temperature in the thermo database [K]
@@ -652,8 +706,8 @@ subroutine ShockSolver_solve_reflected_frozen(self, soln, weights, T0, P0)
652706 dlnV_dlnP = soln% eq_partials(idx)% dlnV_dlnP
653707 dlnV_dlnT = soln% eq_partials(idx)% dlnV_dlnT
654708
655- rho12 = wm* t52/ (wm_k* p52)
656- rho52 = 1 ./ rho12
709+ rho25_inv = wm* t52/ (wm_k* p52)
710+ rho52 = 1 ./ rho25_inv
657711 soln% rho52 = rho52
658712 tmp = - mu25rt* rho52/ (rho52 - 1.0d0 )** 2
659713
@@ -677,10 +731,8 @@ subroutine ShockSolver_solve_reflected_frozen(self, soln, weights, T0, P0)
677731 call self% update_solution(soln, X(1 ), X(2 ), p52, t52, i)
678732
679733 if (i == 1 .and. .not. soln% converged .and. t52 >= ttmax) then
680- call log_warning(" ShockSolver_solve_reflected_frozen: first-iteration update hit " // &
681- " temperature cap; marking reflected point as failed." )
682- soln% eq_soln(idx)% T = 0.0d0
683- soln% pressure(idx) = 0.0d0
734+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_reflected_frozen: first-iteration update hit " // &
735+ " temperature cap; marking reflected point as failed." )
684736 return
685737 end if
686738
@@ -701,14 +753,7 @@ subroutine ShockSolver_solve_reflected_frozen(self, soln, weights, T0, P0)
701753
702754 ! Not converged; compute shock properties
703755 if (.not. soln% converged) then
704- soln% rho52 = rho52
705- soln% p52 = p52
706- soln% t52 = t52
707- soln% u(idx) = soln% v2/ rho52
708- soln% M52 = wm_k/ wm
709- soln% mach(idx) = soln% M52* soln% mach(2 )
710- soln% u5_p_v2 = (u1 - u1* rho12)* (1.0d0-1.0d0 / rho52)
711- soln% v_sonic(idx) = (R* T5* (cp/ (cp - 1.0 / wm_k))/ wm_k)** 0.5d0
756+ call ShockSolver_fail_state(soln, idx, " ShockSolver_solve_reflected_frozen: reflected frozen solve did not converge." )
712757 end if
713758
714759 end subroutine
0 commit comments