Skip to content

Commit 598ea93

Browse files
authored
Merge pull request #72 from maresb/refactor-newton
Refactor Newton iteration into a separate function
2 parents 8ead462 + e4f283e commit 598ea93

File tree

1 file changed

+100
-64
lines changed

1 file changed

+100
-64
lines changed

src/tcpyPI/pi.py

Lines changed: 100 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -201,71 +201,14 @@ def cape(TP,RP,PP,T,R,P,ascent_flag=0,ptop=50,miss_handle=1):
201201
# *** Calculate Parcel quantities ABOVE lifted condensation level ***
202202
#
203203
else:
204-
205-
# Initial default values before loop
206-
TGNEW=T[j]
207-
TJC=utilities.T_ktoC(T[j])
208-
ES=utilities.es_cc(TJC)
209-
RG=utilities.rv(ES,P[j])
210-
211-
#
212-
# *** Iteratively calculate lifted parcel temperature and mixing ***
213-
# *** ratio for reversible ascent ***
214-
#
215-
216-
# set loop counter and initial condition
217-
NC=0
218-
TG=0
204+
TG, RG, IFLAG = solve_temperature_from_entropy(S=S, P=P[j], RP=RP, T_initial=T[j])
205+
if IFLAG == 2: # Did not converge
206+
CAPED=0
207+
TOB=T[0]
208+
LNB=P[0]
209+
# Return the uncoverged values
210+
return(CAPED,TOB,LNB,IFLAG)
219211

220-
# loop until loop converges or bails out
221-
while ((np.abs(TGNEW-TG)) > 0.001):
222-
223-
# Parcel temperature and mixing ratio during this iteration
224-
TG=TGNEW
225-
TC=utilities.T_ktoC(TG)
226-
ENEW=utilities.es_cc(TC)
227-
RG=utilities.rv(ENEW,P[j])
228-
229-
# increase iteration count in the loop
230-
NC += 1
231-
232-
#
233-
# *** Calculate estimates of the rates of change of the entropy ***
234-
# *** with temperature at constant pressure ***
235-
#
236-
237-
ALV=utilities.Lv(TC)
238-
# calculate the rate of change of entropy with temperature, s_ell
239-
SL=(constants.CPD+RP*constants.CL+ALV*ALV*RG/(constants.RV*TG*TG))/TG
240-
EM=utilities.ev(RG,P[j])
241-
# calculate the saturated entropy, s_k, noting r_T=RP and
242-
# the last term vanishes with saturation, i.e. RH=1
243-
SG=(constants.CPD+RP*constants.CL)*np.log(TG)-constants.RD*np.log(P[j]-EM)+ALV*RG/TG
244-
# convergence speed (AP, step in entropy fraction) varies as a function of
245-
# number of iterations
246-
if (NC < 3):
247-
# converge slowly with a smaller step
248-
AP=0.3
249-
else:
250-
# speed the process with a larger step when nearing convergence
251-
AP=1.0
252-
# find the new temperature in the iteration
253-
TGNEW=TG+AP*(S-SG)/SL
254-
255-
#
256-
# *** If the routine does not converge, set IFLAG=2 and bail out ***
257-
#
258-
if (NC > 500) or (ENEW > (P[j]-1)):
259-
CAPED=0
260-
TOB=T[0]
261-
LNB=P[0]
262-
IFLAG=2
263-
# Return the uncoverged values
264-
return(CAPED,TOB,LNB,IFLAG)
265-
266-
# store the number of iterations
267-
NCMAX=NC
268-
269212
#
270213
# *** Calculate buoyancy ***
271214
#
@@ -345,7 +288,100 @@ def cape(TP,RP,PP,T,R,P,ascent_flag=0,ptop=50,miss_handle=1):
345288
# Return the calculated outputs to the above program level
346289
return(CAPED,TOB,LNB,IFLAG)
347290

291+
292+
@njit()
293+
def solve_temperature_from_entropy(S, P, RP, T_initial):
294+
"""Compute the temperature corresponding to a given value for saturated entropy.
295+
296+
For given pressure P and dry mixing ratio RP, saturated entropy is a function
297+
of temperature SG(T). This function uses Newton-Raphson iteration to invert
298+
saturated entropy to find the temperature T that satisfies SG(T) = S for
299+
a target value of saturated entropy S.
300+
301+
Args:
302+
S (float): Target saturated entropy (J/kg/K).
303+
P (float): Ambient pressure (hPa).
304+
RP (float): Parcel mixing ratio for the dry component (g/g).
305+
T_initial (float): Initial guess for temperature (K).
306+
307+
Returns:
308+
tuple: (TG, RG, IFLAG) where:
309+
TG (float): Temperature (K) satisfying SG(T) = S.
310+
RG (float): Computed saturated mixing ratio (g/g).
311+
IFLAG (int): Status flag where:
312+
1 = Success
313+
2 = Did not converge
314+
315+
Examples:
316+
>>> S = 4000
317+
>>> P = 1000
318+
>>> RP = 0.01
319+
>>> TG, RG, IFLAG = solve_temperature_from_entropy(S, P, RP, T_initial=300)
320+
>>> print(f"TG: {TG}, RG: {RG}, IFLAG: {IFLAG}")
321+
TG: 292.676..., RG: 0.0144..., IFLAG: 1
322+
"""
323+
# Initial default values before loop
324+
TGNEW=T_initial
325+
TJC=utilities.T_ktoC(T_initial)
326+
ES=utilities.es_cc(TJC)
327+
RG=utilities.rv(ES,P)
348328

329+
#
330+
# *** Iteratively calculate lifted parcel temperature and mixing ***
331+
# *** ratio for reversible ascent ***
332+
#
333+
334+
# set loop counter and initial condition
335+
NC=0
336+
TG=0
337+
338+
# loop until loop converges or bails out
339+
while ((np.abs(TGNEW-TG)) > 0.001):
340+
341+
# Parcel temperature and mixing ratio during this iteration
342+
TG=TGNEW
343+
TC=utilities.T_ktoC(TG)
344+
ENEW=utilities.es_cc(TC)
345+
RG=utilities.rv(ENEW,P)
346+
347+
# increase iteration count in the loop
348+
NC += 1
349+
350+
#
351+
# *** Calculate estimates of the rates of change of the entropy ***
352+
# *** with temperature at constant pressure ***
353+
#
354+
355+
ALV=utilities.Lv(TC)
356+
# calculate the rate of change of entropy with temperature, s_ell
357+
SL=(constants.CPD+RP*constants.CL+ALV*ALV*RG/(constants.RV*TG*TG))/TG
358+
EM=utilities.ev(RG,P)
359+
# calculate the saturated entropy, s_k, noting r_T=RP and
360+
# the last term vanishes with saturation, i.e. RH=1
361+
SG=(constants.CPD+RP*constants.CL)*np.log(TG)-constants.RD*np.log(P-EM)+ALV*RG/TG
362+
# convergence speed (AP, step in entropy fraction) varies as a function of
363+
# number of iterations
364+
if (NC < 3):
365+
# converge slowly with a smaller step
366+
AP=0.3
367+
else:
368+
# speed the process with a larger step when nearing convergence
369+
AP=1.0
370+
# find the new temperature in the iteration
371+
TGNEW=TG+AP*(S-SG)/SL
372+
373+
#
374+
# *** If the routine does not converge, set IFLAG=2 and bail out ***
375+
#
376+
if (NC > 500) or (ENEW > (P-1)):
377+
IFLAG = 2 # Did not converge
378+
return TG, RG, IFLAG
379+
380+
# store the number of iterations
381+
NCMAX=NC
382+
383+
IFLAG = 1 # Success
384+
return TG, RG, IFLAG
349385

350386

351387
# define the function to calculate PI

0 commit comments

Comments
 (0)