@@ -295,9 +295,9 @@ def moist_lapse(pressure, temperature, reference_pressure=None):
295295 Renamed ``ref_pressure`` parameter to ``reference_pressure``
296296
297297 """
298- def dt (t , p ):
299- t = units .Quantity (t , temperature . units )
300- p = units .Quantity (p , pressure . units )
298+ def dt (p , t ):
299+ t = units .Quantity (t , 'kelvin' )
300+ p = units .Quantity (p , 'mbar' )
301301 rs = saturation_mixing_ratio (p , t )
302302 frac = ((mpconsts .Rd * t + mpconsts .Lv * rs )
303303 / (mpconsts .Cp_d + (mpconsts .Lv * mpconsts .Lv * rs * mpconsts .epsilon
@@ -307,39 +307,55 @@ def dt(t, p):
307307 pressure = np .atleast_1d (pressure )
308308 if reference_pressure is None :
309309 reference_pressure = pressure [0 ]
310-
311- if np .isnan (reference_pressure ):
312- return units .Quantity (np .full (pressure .shape , np .nan ), temperature .units )
313-
314310 pressure = pressure .to ('mbar' )
315311 reference_pressure = reference_pressure .to ('mbar' )
316312 org_units = temperature .units
317- temperature = np .atleast_1d (temperature ).to ('kelvin' )
313+ temperature = np .atleast_1d (temperature ).m_as ('kelvin' )
314+
315+ if np .isnan (reference_pressure ) or np .all (np .isnan (temperature )):
316+ return units .Quantity (np .full ((temperature .size , pressure .size ), np .nan ), org_units )
318317
319318 pres_decreasing = (pressure [0 ] > pressure [- 1 ])
320319 if pres_decreasing :
321320 # Everything is easier if pressures are in increasing order
322321 pressure = pressure [::- 1 ]
323322
324- ref_pres_idx = np .searchsorted (pressure .m , reference_pressure .m , side = 'right' )
325- ret_temperatures = np .empty ((0 , temperature .shape [0 ]))
323+ # It would be preferable to use a regular solver like RK45, but as of scipy 1.8.0
324+ # anything other than LSODA goes into an infinite loop when given NaNs for y0.
325+ solver_args = {'fun' : dt , 'y0' : temperature ,
326+ 'method' : 'LSODA' , 'atol' : 1e-7 , 'rtol' : 1.5e-8 }
326327
327- if _greater_or_close (reference_pressure , pressure .min ()):
328- # Integrate downward in pressure
329- pres_down = np .append (reference_pressure .m , pressure [(ref_pres_idx - 1 )::- 1 ].m )
330- trace_down = si .odeint (dt , temperature .m .squeeze (), pres_down .squeeze ())
331- ret_temperatures = np .concatenate ((ret_temperatures , trace_down [:0 :- 1 ]))
332-
333- if reference_pressure < pressure .max ():
334- # Integrate upward in pressure
335- pres_up = np .append (reference_pressure .m , pressure [ref_pres_idx :].m )
336- trace_up = si .odeint (dt , temperature .m .squeeze (), pres_up .squeeze ())
337- ret_temperatures = np .concatenate ((ret_temperatures , trace_up [1 :]))
328+ # Need to handle close points to avoid an error in the solver
329+ close = np .isclose (pressure , reference_pressure )
330+ if np .any (close ):
331+ ret = np .broadcast_to (temperature [:, np .newaxis ], (temperature .size , np .sum (close )))
332+ else :
333+ ret = np .empty ((temperature .size , 0 ), dtype = temperature .dtype )
334+
335+ # Do we have any points above the reference pressure
336+ points_above = (pressure < reference_pressure ) & ~ close
337+ if np .any (points_above ):
338+ # Integrate upward--need to flip so values are properly ordered from ref to min
339+ press_side = pressure [points_above ][::- 1 ].m
340+
341+ # Flip on exit so t values correspond to increasing pressure
342+ trace = si .solve_ivp (t_span = (reference_pressure .m , press_side [- 1 ]),
343+ t_eval = press_side , ** solver_args ).y [..., ::- 1 ]
344+ ret = np .concatenate ((trace , ret ), axis = - 1 )
345+
346+ # Do we have any points below the reference pressure
347+ points_below = ~ points_above & ~ close
348+ if np .any (points_below ):
349+ # Integrate downward
350+ press_side = pressure [points_below ].m
351+ trace = si .solve_ivp (t_span = (reference_pressure .m , press_side [- 1 ]),
352+ t_eval = press_side , ** solver_args ).y
353+ ret = np .concatenate ((ret , trace ), axis = - 1 )
338354
339355 if pres_decreasing :
340- ret_temperatures = ret_temperatures [ ::- 1 ]
356+ ret = ret [..., ::- 1 ]
341357
342- return units .Quantity (ret_temperatures . T .squeeze (), 'kelvin' ).to (org_units )
358+ return units .Quantity (ret .squeeze (), 'kelvin' ).to (org_units )
343359
344360
345361@exporter .export
0 commit comments