paddle 1.2.0__py3-none-any.whl → 1.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
paddle/__init__.py CHANGED
@@ -4,4 +4,4 @@ from .find_init_params import find_init_params
4
4
  from .evolve_kinetics import evolve_kinetics
5
5
 
6
6
  __all__ = ["setup_profile", "write_profile", "find_init_params", "evolve_kinetics"]
7
- __version__ = "1.2.0"
7
+ __version__ = "1.2.1"
@@ -0,0 +1,63 @@
1
+ import numpy as np
2
+ import matplotlib.pyplot as plt
3
+ from matplotlib.widgets import Slider, CheckButtons, Button
4
+ from cubed_sphere_utils import draw_panel_corner
5
+
6
+ plt.close("all")
7
+ fig = plt.figure(figsize=(9, 7))
8
+ ax = fig.add_axes([0.08, 0.18, 0.82, 0.75])
9
+ ax.set_aspect("equal")
10
+ ax.set_xlim(-1.05, 1.05)
11
+ ax.set_ylim(-1.05, 1.05)
12
+ ax.set_title(
13
+ "Interactive orthographic view — drag sliders to rotate view_dir\n(+X solid, +Y dotted, +Z dash-dot; ghosts dashed)"
14
+ )
15
+
16
+ ax_az = fig.add_axes([0.08, 0.10, 0.6, 0.03])
17
+ ax_el = fig.add_axes([0.08, 0.06, 0.6, 0.03])
18
+ s_az = Slider(ax_az, "Azimuth (°)", 0, 360, valinit=45, valstep=1)
19
+ s_el = Slider(ax_el, "Elevation (°)", -85, 85, valinit=10, valstep=1)
20
+
21
+ ax_chk = fig.add_axes([0.72, 0.05, 0.18, 0.10])
22
+ checks = CheckButtons(ax_chk, labels=["Show +Z"], actives=[True])
23
+
24
+ ax_reset = fig.add_axes([0.65, 0.12, 0.1, 0.04])
25
+ btn_reset = Button(ax_reset, "Reset")
26
+
27
+
28
+ def viewdir_from_angles(az_deg, el_deg):
29
+ az = np.deg2rad(az_deg)
30
+ el = np.deg2rad(el_deg)
31
+ c = np.cos(el)
32
+ return np.array([c * np.cos(az), c * np.sin(az), np.sin(el)])
33
+
34
+
35
+ def redraw(_=None):
36
+ ax.cla()
37
+ ax.set_aspect("equal")
38
+ ax.set_xlim(-1.1, 1.1)
39
+ ax.set_ylim(-1.1, 1.1)
40
+ ax.set_title(
41
+ "Interactive orthographic view — drag sliders to rotate view_dir\n(+X solid, +Y dotted, +Z dash-dot; ghosts dashed)"
42
+ )
43
+ V = viewdir_from_angles(s_az.val, s_el.val)
44
+
45
+ draw_panel_corner(ax, N=8, nghost=3, view_dir=V)
46
+
47
+ fig.canvas.draw_idle()
48
+
49
+
50
+ def on_reset(event):
51
+ s_az.reset()
52
+ s_el.reset()
53
+ if not checks.get_status()[0]:
54
+ checks.set_active(0)
55
+
56
+
57
+ s_az.on_changed(redraw)
58
+ s_el.on_changed(redraw)
59
+ checks.on_clicked(redraw)
60
+ btn_reset.on_clicked(on_reset)
61
+
62
+ redraw()
63
+ plt.show()
@@ -0,0 +1,356 @@
1
+ import numpy as np
2
+ from matplotlib.patches import Polygon
3
+ from typing import Tuple
4
+
5
+
6
+ def normalize(v: np.ndarray) -> np.ndarray:
7
+ return v / np.linalg.norm(v)
8
+
9
+
10
+ def gnomonic_equiangular_to_xyz(alpha, beta, face="+X"):
11
+ """
12
+ Map equiangular gnomonic coordinates (alpha, beta) in radians to
13
+ Cartesian coordinates (x, y, z) on the unit sphere for a given cube face.
14
+
15
+ (alpha, beta) are the equiangular angles from the face center:
16
+ t = tan(alpha), u = tan(beta)
17
+ Faces: "+X", "-X", "+Y", "-Y", "+Z", "-Z"
18
+ """
19
+ t = np.tan(alpha)
20
+ u = np.tan(beta)
21
+
22
+ if face == "+X":
23
+ X, Y, Z = np.ones_like(t), t, u
24
+ elif face == "-X":
25
+ X, Y, Z = -np.ones_like(t), -t, u
26
+ elif face == "+Y":
27
+ X, Y, Z = -t, np.ones_like(t), u
28
+ elif face == "-Y":
29
+ X, Y, Z = t, -np.ones_like(t), u
30
+ elif face == "+Z":
31
+ X, Y, Z = -u, t, np.ones_like(t)
32
+ elif face == "-Z":
33
+ X, Y, Z = u, t, -np.ones_like(t)
34
+ else:
35
+ raise ValueError("Invalid face specifier")
36
+
37
+ inv_norm = 1.0 / np.sqrt(X * X + Y * Y + Z * Z)
38
+ return X * inv_norm, Y * inv_norm, Z * inv_norm
39
+
40
+
41
+ def orthographic_project(face_xyz, view_dir=np.array([1, 0, 0])):
42
+ """Orthographic projection onto the plane normal to view_dir."""
43
+ x, y, z = face_xyz
44
+ V = normalize(np.array(view_dir))
45
+ # Construct orthonormal basis (e1,e2) spanning plane perpendicular to V
46
+ # Choose arbitrary "up" vector not parallel to V
47
+ up_guess = np.array([0, 0, 1]) if abs(V[2]) < 0.9 else np.array([0, 1, 0])
48
+ e1 = normalize(np.cross(up_guess, V))
49
+ e2 = np.cross(V, e1)
50
+ # Project coordinates
51
+ U = x * e1[0] + y * e1[1] + z * e1[2]
52
+ W = x * e2[0] + y * e2[1] + z * e2[2]
53
+ return U, W
54
+
55
+
56
+ def visible_segments(u, v, depth, vis_mask):
57
+ segs = []
58
+ start = None
59
+ for i in range(len(u)):
60
+ if vis_mask[i] and start is None:
61
+ start = i
62
+ elif (not vis_mask[i]) and (start is not None):
63
+ segs.append((u[start:i], v[start:i], depth[start:i]))
64
+ start = None
65
+ if start is not None:
66
+ segs.append((u[start:], v[start:], depth[start:]))
67
+ return segs
68
+
69
+
70
+ def plot_on_face(ax, alpha, beta, face="+X", view_dir=np.array([1, 0, 0]), **kwargs):
71
+ x, y, z = gnomonic_equiangular_to_xyz(alpha, beta, face=face)
72
+ # r·V (nearness for ortho)
73
+ depth = x * view_dir[0] + y * view_dir[1] + z * view_dir[2]
74
+
75
+ vis = depth > 0 # front hemisphere
76
+ u, v = orthographic_project((x, y, z), view_dir=view_dir)
77
+ segs = visible_segments(u, v, depth, vis)
78
+ segs.sort(key=lambda seg: np.max(seg[2]) if seg[2].size else -1)
79
+ for uu, vv, dd in segs:
80
+ ax.plot(uu, vv, zorder=np.max(dd) if dd.size else 0, **kwargs)
81
+
82
+
83
+ def scatter_on_face(ax, alpha, beta, face="+X", view_dir=np.array([1, 0, 0]), **kwargs):
84
+ x, y, z = gnomonic_equiangular_to_xyz(alpha, beta, face=face)
85
+ # r·V (nearness for ortho)
86
+ depth = x * view_dir[0] + y * view_dir[1] + z * view_dir[2]
87
+
88
+ vis = depth > 0 # front hemisphere
89
+ u, v = orthographic_project((x, y, z), view_dir=view_dir)
90
+ ax.scatter(u[vis], v[vis], zorder=np.max(depth[vis]), **kwargs)
91
+
92
+
93
+ def panel_ab_limits(
94
+ dxy, N, nghost, exterior=True
95
+ ) -> Tuple[Tuple[float, float], Tuple[float, float]]:
96
+ """
97
+ Return ((a_min, b_min), (a_max, b_max)) in equiangular gnomonic coords (radians)
98
+ for a single cubed-sphere panel.
99
+
100
+ Panel interior spans α,β ∈ [-π/4, +π/4]. Each cell has angular size
101
+ dθ = (π/2) / N. Ghost zones extend outward by 'nghost' cells.
102
+
103
+ Offsets (dx, dy) ∈ {-1, 0, 1} select a slab/corner in each dimension:
104
+ - dx = -1: left
105
+ - dx = 0: center
106
+ - dx = +1: right
107
+ (analogous for dy: bottom/center/top)
108
+
109
+ exterior=True:
110
+ - (0, 0) returns FULL exterior limits including ghost zones
111
+ - (-1, 0) returns the LEFT ghost region only (width = nghost * dθ), etc.
112
+
113
+ exterior=False:
114
+ - (0, 0) returns interior limits ONLY
115
+ - (-1, 0) returns the interior boundary slab adjacent to the left edge,
116
+ with the SAME thickness as the ghost zone (nghost * dθ) but inside.
117
+ (Analogous for other offsets and for dy.)
118
+
119
+ Returns:
120
+ ((a_min, b_min), (a_max, b_max))
121
+ """
122
+ dx, dy = dxy
123
+ if dx not in (-1, 0, 1) or dy not in (-1, 0, 1):
124
+ raise ValueError("dx, dy must be in {-1, 0, 1}")
125
+ if N <= 0 or nghost < 0:
126
+ raise ValueError("N must be > 0 and nghost >= 0")
127
+
128
+ dtheta = (np.pi / 2.0) / N
129
+ aL_int, aR_int = -np.pi / 4, +np.pi / 4
130
+ bB_int, bT_int = -np.pi / 4, +np.pi / 4
131
+
132
+ # External (interior + ghosts) bounds along each dimension
133
+ aL_ext = aL_int - nghost * dtheta
134
+ aR_ext = aR_int + nghost * dtheta
135
+ bB_ext = bB_int - nghost * dtheta
136
+ bT_ext = bT_int + nghost * dtheta
137
+
138
+ def one_dim_limits(
139
+ offset: int, L_int: float, R_int: float, L_ext: float, R_ext: float
140
+ ):
141
+ if offset == 0: # full span incl. ghosts
142
+ return (L_int, R_int)
143
+ if exterior:
144
+ if offset == -1: # left ghost slab
145
+ return (L_ext, L_int)
146
+ else: # +1: right ghost slab
147
+ return (R_int, R_ext)
148
+ else:
149
+ if offset == -1: # interior boundary slab (left), same thickness as ghosts
150
+ return (L_int, L_int + nghost * dtheta)
151
+ else: # +1: interior boundary slab (right)
152
+ return (R_int - nghost * dtheta, R_int)
153
+
154
+ a_min, a_max = one_dim_limits(dx, aL_int, aR_int, aL_ext, aR_ext)
155
+ b_min, b_max = one_dim_limits(dy, bB_int, bT_int, bB_ext, bT_ext)
156
+
157
+ # set to whole domain
158
+ if dx == 0 and dy == 0 and exterior:
159
+ a_min, a_max = aL_ext, aR_ext
160
+ b_min, b_max = bB_ext, bT_ext
161
+
162
+ # Ensure (lower-left, upper-right) ordering
163
+ a0, a1 = (min(a_min, a_max), max(a_min, a_max))
164
+ b0, b1 = (min(b_min, b_max), max(b_min, b_max))
165
+ return (a0, b0), (a1, b1)
166
+
167
+
168
+ def sample_edge(a0, b0, a1, b1, n_pts=64):
169
+ t = np.linspace(0.0, 1.0, n_pts)
170
+ return (a0 + (a1 - a0) * t), (b0 + (b1 - b0) * t)
171
+
172
+
173
+ def make_poly_patch(verts_ab, face="+X", view_dir=(1, 0, 0), n_pts=64, **kwargs):
174
+ # Sample each edge, map to sphere, cull back hemisphere
175
+ boundary_u, boundary_v, boundary_d = [], [], []
176
+ for (a0, b0), (a1, b1) in zip(verts_ab, verts_ab[1:] + verts_ab[:1]):
177
+ aa, bb = sample_edge(a0, b0, a1, b1, n_pts=n_pts)
178
+ xyz = gnomonic_equiangular_to_xyz(aa, bb, face=face)
179
+ u, v = orthographic_project(xyz, view_dir=view_dir)
180
+ d = xyz[0] * view_dir[0] + xyz[1] * view_dir[1] + xyz[2] * view_dir[2]
181
+ mask = d > 0
182
+ boundary_u.append(u[mask])
183
+ boundary_v.append(v[mask])
184
+ boundary_d.append(d[mask])
185
+
186
+ if not any(len(u) for u in boundary_u):
187
+ return None # fully occluded
188
+
189
+ U = np.concatenate(boundary_u)
190
+ V = np.concatenate(boundary_v)
191
+ D = (
192
+ np.concatenate(boundary_d)
193
+ if any(len(d) for d in boundary_d)
194
+ else np.array([0.0])
195
+ )
196
+
197
+ poly = Polygon(np.c_[U, V], closed=True, zorder=1 + float(np.max(D)), **kwargs)
198
+ return poly
199
+
200
+
201
+ def draw_panel_grid(
202
+ ax,
203
+ face="+X",
204
+ N=8,
205
+ nghost=3,
206
+ n_pts=800,
207
+ view_dir=np.array([1, 0, 0]),
208
+ color="C0",
209
+ linestyle="--",
210
+ linewidth=0.8,
211
+ facecolor="none",
212
+ ):
213
+ """
214
+ Plot an equiangular gnomonic grid for a single cubed-sphere panel with ghost zones.
215
+ - N: number of interior cells per direction (there are N+1 interior grid lines).
216
+ - nghost: number of extra ghost cells beyond each edge (drawn dashed).
217
+ """
218
+ # Uniform grid in equiangular coordinates; panel spans [-pi/4, +pi/4].
219
+ dtheta = (np.pi / 2) / N # cell size in angle
220
+
221
+ # Grid-line indices: i = -N/2 ... N/2 for interior; extend by nghost
222
+ halfN = N // 2
223
+ idx = np.arange(-halfN - nghost, halfN + nghost + 1)
224
+ alphas = idx * dtheta # positions of grid lines
225
+ centers = 0.5 * (alphas[1:] + alphas[:-1]) # cell centers
226
+
227
+ # Limit plotting domain to a slightly larger band so dashed ghost lines are visible
228
+ s = np.linspace(-np.pi / 4 - nghost * dtheta, np.pi / 4 + nghost * dtheta, n_pts)
229
+
230
+ # alpha = const lines
231
+ for i, alpha in zip(idx, alphas):
232
+ # skip the first and the last lines
233
+ if i == idx[0] or i == idx[-1]:
234
+ continue
235
+ plot_on_face(
236
+ ax,
237
+ np.full_like(s, alpha),
238
+ s,
239
+ face=face,
240
+ view_dir=view_dir,
241
+ linewidth=linewidth,
242
+ linestyle=linestyle,
243
+ color=color,
244
+ )
245
+
246
+ # beta = const lines
247
+ for j, beta in zip(idx, alphas):
248
+ # skip the first and the last lines
249
+ if j == idx[0] or j == idx[-1]:
250
+ continue
251
+ plot_on_face(
252
+ ax,
253
+ s,
254
+ np.full_like(s, beta),
255
+ face=face,
256
+ view_dir=view_dir,
257
+ linewidth=linewidth,
258
+ linestyle=linestyle,
259
+ color=color,
260
+ )
261
+
262
+ # cell centers (solid dots)
263
+ center_a, center_b = np.meshgrid(centers, centers)
264
+ scatter_on_face(
265
+ ax,
266
+ center_a.flatten(),
267
+ center_b.flatten(),
268
+ face=face,
269
+ view_dir=view_dir,
270
+ s=10,
271
+ facecolors=facecolor,
272
+ edgecolors=color,
273
+ )
274
+
275
+ # Interior panel boundary (bold): |alpha|=pi/4 and |beta|=pi/4
276
+ for alpha in [-np.pi / 4, np.pi / 4]:
277
+ plot_on_face(
278
+ ax,
279
+ np.full_like(s, alpha),
280
+ s,
281
+ face=face,
282
+ view_dir=view_dir,
283
+ linestyle="-.",
284
+ linewidth=1.6,
285
+ color=color,
286
+ )
287
+ for beta in [-np.pi / 4, np.pi / 4]:
288
+ plot_on_face(
289
+ ax,
290
+ s,
291
+ np.full_like(s, beta),
292
+ face=face,
293
+ view_dir=view_dir,
294
+ linestyle="-.",
295
+ linewidth=1.6,
296
+ color=color,
297
+ )
298
+
299
+
300
+ def draw_single_panel(
301
+ ax, face="+X", N=8, nghost=3, color="C0", view_dir=np.array([1, 0, 0])
302
+ ):
303
+ # all grid lines including ghosts
304
+ draw_panel_grid(ax, face=face, N=N, nghost=nghost, color=color, view_dir=view_dir)
305
+
306
+ # interior grid lines only
307
+ draw_panel_grid(
308
+ ax,
309
+ face=face,
310
+ N=N,
311
+ nghost=0,
312
+ view_dir=view_dir,
313
+ linestyle="-",
314
+ linewidth=1.2,
315
+ facecolor=color,
316
+ color=color,
317
+ )
318
+
319
+
320
+ def draw_panel_seam(ax, N=8, nghost=3, view_dir=np.array([1.0, 1.0, 0.0])):
321
+ draw_single_panel(ax, "+X", N=N, nghost=nghost, view_dir=view_dir, color="C0")
322
+ draw_single_panel(ax, "+Y", N=N, nghost=nghost, view_dir=view_dir, color="C1")
323
+
324
+ # ghost zone patches
325
+ (a0, b0), (a1, b1) = panel_ab_limits((1, 0), N=N, nghost=nghost, exterior=True)
326
+ verts_box = [(a0, b0), (a1, b0), (a1, b1), (a0, b1)]
327
+ poly = make_poly_patch(
328
+ verts_box,
329
+ face="+X",
330
+ view_dir=view_dir,
331
+ edgecolor="k",
332
+ # grey with some transparency
333
+ facecolor=(0.5, 0.5, 0.5, 0.3),
334
+ linewidth=1.2,
335
+ )
336
+ ax.add_patch(poly)
337
+
338
+
339
+ def draw_panel_corner(ax, N=8, nghost=3, view_dir=np.array([1.0, 1.0, 1.0])):
340
+ draw_single_panel(ax, "+X", N=N, nghost=nghost, view_dir=view_dir, color="C0")
341
+ draw_single_panel(ax, "+Y", N=N, nghost=nghost, view_dir=view_dir, color="C1")
342
+ draw_single_panel(ax, "+Z", N=N, nghost=nghost, view_dir=view_dir, color="C2")
343
+
344
+ # ghost zone patches
345
+ (a0, b0), (a1, b1) = panel_ab_limits((1, 1), N=N, nghost=nghost, exterior=True)
346
+ verts_box = [(a0, b0), (a1, b0), (a1, b1), (a0, b1)]
347
+ poly = make_poly_patch(
348
+ verts_box,
349
+ face="+X",
350
+ view_dir=view_dir,
351
+ edgecolor="k",
352
+ # grey with some transparency
353
+ facecolor=(0.5, 0.5, 0.5, 0.3),
354
+ linewidth=1.2,
355
+ )
356
+ ax.add_patch(poly)
paddle/evolve_kinetics.py CHANGED
@@ -6,9 +6,10 @@ from snapy import kIDN, kIPR, kICY
6
6
 
7
7
  def evolve_kinetics(
8
8
  hydro_w: torch.Tensor,
9
- block: snapy.MeshBlock,
10
- kinet: kintera.Kinetics,
9
+ eos: snapy.EquationOfState,
11
10
  thermo_x: kintera.ThermoX,
11
+ thermo_y: kintera.ThermoY,
12
+ kinet: kintera.Kinetics,
12
13
  dt,
13
14
  ) -> torch.Tensor:
14
15
  """
@@ -16,30 +17,45 @@ def evolve_kinetics(
16
17
 
17
18
  Args:
18
19
  hydro_w (torch.Tensor): The primitive variables tensor.
19
- block (snapy.MeshBlock): The mesh block containing the simulation data.
20
- kinet (kintera.Kinetics): The kinetics module for chemical reactions.
20
+ eos (snapy.EquationOfState): The equation-of-state.
21
21
  thermo_x (kintera.ThermoX): The thermodynamics module for computing properties.
22
+ thermo_y (kintera.ThermoY): The thermodynamics module for computing properties.
23
+ kinet (kintera.Kinetics): The kinetics module for chemical reactions.
22
24
  dt (float): The time step for evolution.
23
25
 
24
26
  Returns:
25
27
  torch.Tensor: The change in mass density due to chemical reactions.
26
28
  """
27
- eos = block.hydro.get_eos()
28
- thermo_y = block.module("hydro.eos.thermo")
29
-
29
+ # compute temperature and pressure
30
30
  temp = eos.compute("W->T", (hydro_w,))
31
31
  pres = hydro_w[kIPR]
32
+
33
+ # compute mole fractions from mass fractions
32
34
  xfrac = thermo_y.compute("Y->X", (hydro_w[kICY:],))
35
+
36
+ # compute molar concentrations
33
37
  conc = thermo_x.compute("TPX->V", (temp, pres, xfrac))
38
+
39
+ # compute volumetric heat capacity
34
40
  cp_vol = thermo_x.compute("TV->cp", (temp, conc))
35
41
 
36
- conc_kinet = kinet.options.narrow_copy(conc, thermo_y.options)
42
+ # narrow species for kinetics
43
+ # conc_kinet = kinet.options.narrow_copy(conc, thermo_y.options)
44
+ conc_kinet = conc[:, :, :, 1:] # exclude dry species
45
+
46
+ # compute rate and rate jacobians
37
47
  rate, rc_ddC, rc_ddT = kinet.forward_nogil(temp, pres, conc_kinet)
48
+
49
+ # compute reaction jacobian
38
50
  jac = kinet.jacobian(temp, conc_kinet, cp_vol, rate, rc_ddC, rc_ddT)
39
51
 
52
+ # compute concentration change
40
53
  stoich = kinet.buffer("stoich")
41
54
  del_conc = kintera.evolve_implicit(rate, stoich, jac, dt)
42
55
 
56
+ # compute density change
43
57
  inv_mu = thermo_y.buffer("inv_mu")
44
58
  del_rho = del_conc / inv_mu[1:].view(1, 1, 1, -1)
59
+
60
+ # return permutated density change for hydro
45
61
  return del_rho.permute(3, 0, 1, 2)
@@ -34,7 +34,7 @@ def find_init_params(
34
34
  dict: Dictionary containing the found parameters: Ts, Ps, xH2O, xNH3, xH2S.
35
35
  """
36
36
  count = 0
37
- eos = block.hydro.get_eos()
37
+ eos = block.module("hydro.eos")
38
38
 
39
39
  while count < max_iter:
40
40
  if verbose:
@@ -0,0 +1,21 @@
1
+ import matplotlib.pyplot as plt
2
+ from cubed_sphere_utils import (
3
+ make_poly_patch,
4
+ draw_single_panel,
5
+ draw_panel_seam,
6
+ draw_panel_corner,
7
+ )
8
+
9
+ if __name__ == "__main__":
10
+ fig, ax = plt.subplots(figsize=(8, 8))
11
+
12
+ # draw_single_panel(ax, N=6, nghost=3)
13
+ draw_panel_seam(ax, N=6, nghost=2)
14
+ # draw_panel_corner(ax, N=8, nghost=3)
15
+
16
+ ax.set_aspect("equal")
17
+ ax.set_xlabel("X (orthographic)")
18
+ ax.set_ylabel("Y (orthographic)")
19
+ ax.set_xlim(-1.1, 1.1)
20
+ ax.set_ylim(-1.1, 1.1)
21
+ plt.show()
paddle/setup_profile.py CHANGED
@@ -34,7 +34,7 @@ def integrate_neutral(
34
34
  pres_ad = pres.clone()
35
35
  xfrac_ad = xfrac.clone()
36
36
 
37
- thermo_x.extrapolate_ad(temp_ad, pres_ad, xfrac_ad, grav, dz)
37
+ thermo_x.extrapolate_dz(temp_ad, pres_ad, xfrac_ad, dz, grav=grav)
38
38
  conc_ad = thermo_x.compute("TPX->V", [temp_ad, pres_ad, xfrac_ad])
39
39
  rho_ad = thermo_x.compute("V->D", [conc_ad])
40
40
  rho_bar = 0.5 * (rho + rho_ad)
@@ -192,7 +192,7 @@ def setup_profile(
192
192
  Tmin = param.get("Tmin", 0.0)
193
193
 
194
194
  # get handles to modules
195
- coord = block.module("hydro.coord")
195
+ coord = block.module("coord")
196
196
  thermo_y = block.module("hydro.eos.thermo")
197
197
 
198
198
  # get coordinates
@@ -224,23 +224,26 @@ def setup_profile(
224
224
 
225
225
  # start and end indices for the vertical direction
226
226
  # excluding ghost cells
227
- ifirst = coord.ifirst()
228
- ilast = coord.ilast()
227
+ il = coord.il()
228
+ iu = coord.iu()
229
229
 
230
230
  # vertical grid distance of the first cell
231
- dz = coord.buffer("dx1f")[ifirst]
231
+ dz = coord.buffer("dx1f")[il]
232
232
 
233
233
  # half a grid to cell center
234
- thermo_x.extrapolate_ad(temp, pres, xfrac, grav, dz / 2.0, verbose=verbose)
234
+ rainout = method.split("-")[0] != "moist"
235
+ thermo_x.extrapolate_dz(
236
+ temp, pres, xfrac, dz / 2.0, grav=grav, verbose=verbose, rainout=rainout
237
+ )
235
238
 
236
239
  # adiabatic extrapolation
237
240
  if method == "isothermal":
238
- i_isothermal = ifirst
239
- ifirst = ilast
241
+ i_isothermal = il
242
+ il = iu
240
243
  else:
241
- i_isothermal = ilast
244
+ i_isothermal = iu
242
245
 
243
- for i in range(ifirst, ilast):
246
+ for i in range(il, iu + 1):
244
247
  # drop clouds fractions
245
248
  if method.split("-")[0] != "moist":
246
249
  for cid in thermo_x.options.cloud_ids():
@@ -261,14 +264,16 @@ def setup_profile(
261
264
  elif method.split("-")[0] == "neutral":
262
265
  temp, pres, xfrac = integrate_neutral(thermo_x, temp, pres, xfrac, grav, dz)
263
266
  else:
264
- thermo_x.extrapolate_ad(temp, pres, xfrac, grav, dz, verbose=verbose)
267
+ thermo_x.extrapolate_dz(
268
+ temp, pres, xfrac, dz, grav=grav, verbose=verbose, rainout=rainout
269
+ )
265
270
 
266
271
  if torch.any(temp < Tmin):
267
272
  i_isothermal = i + 1
268
273
  break
269
274
 
270
275
  # isothermal extrapolation
271
- for i in range(i_isothermal, ilast):
276
+ for i in range(i_isothermal, iu + 1):
272
277
  # drop clouds fractions
273
278
  if method.split("-")[0] != "moist":
274
279
  for cid in thermo_x.options.cloud_ids():
paddle/write_profile.py CHANGED
@@ -11,8 +11,8 @@ from snapy import kIPR, kICY
11
11
 
12
12
  def write_profile(
13
13
  filename: str,
14
- hydro_w: torch.Tensor,
15
14
  block: snapy.MeshBlock,
15
+ hydro_w: torch.Tensor,
16
16
  ref_pressure: float = 1.0e5,
17
17
  comment: Optional[str] = None,
18
18
  ) -> None:
@@ -30,9 +30,9 @@ def write_profile(
30
30
  None
31
31
  """
32
32
  # useful modules
33
+ coord = block.module("coord")
33
34
  thermo_y = block.module("hydro.eos.thermo")
34
- coord = block.module("hydro.coord")
35
- eos = block.hydro.get_eos()
35
+ eos = block.module("hydro.eos")
36
36
 
37
37
  # handling mole fraction quantities
38
38
  thermo_x = kintera.ThermoX(thermo_y.options)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: paddle
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: Python Atmospheric Dynamics: Discovery and Learning about Exoplanets. An open-source, user-friendly python frontend of canoe
5
5
  Project-URL: Homepage, https://github.com/elijah-mullens/paddle
6
6
  Project-URL: Repository, https://github.com/elijah-mullens/paddle
@@ -23,7 +23,7 @@ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
23
23
  Classifier: Topic :: Scientific/Engineering :: Physics
24
24
  Requires-Python: >=3.9
25
25
  Requires-Dist: scipy
26
- Requires-Dist: snapy>=1.0.3
26
+ Requires-Dist: snapy>=1.1.5
27
27
  Requires-Dist: torch<=2.7.1,>=2.7.0
28
28
  Provides-Extra: dev
29
29
  Requires-Dist: pytest>=7; extra == 'dev'
@@ -0,0 +1,17 @@
1
+ paddle/__init__.py,sha256=5ok62AfaUnZjwQaQ1A0QyHbMVT917lha7Tsz-TiFJus,281
2
+ paddle/crm.py,sha256=pME4nF5gjlJm-36yMl0N8bzT6UBr2CsOD6nopby7e9M,1993
3
+ paddle/cubed_sphere_ui.py,sha256=2oYfAje6ALuT21fRMFKLYigr59yWDdP3_y6dZ8B4j44,1732
4
+ paddle/cubed_sphere_utils.py,sha256=c7vr0S7JEiMy5UjmEK51gmGZY0j144UjVRsp2wO-iig,11686
5
+ paddle/evolve_kinetics.py,sha256=dMphJqggu18yVqfdcKHbaxkXZhifBfvNjMiDLbdxaOg,2020
6
+ paddle/example_save.py,sha256=MYVOr9J5oTU2NILPnr3qhHdbU7u81Rtca8RjVv8xE6s,610
7
+ paddle/find_init_params.py,sha256=h7ka8fREXjD2RmhflWpByWHFhKoHNCYGN4TATQY0FYg,2532
8
+ paddle/nc2pt.py,sha256=LXR0fnUTaOA_uaDsLU4YqdAVFyycB6SvRq12xWhHhLA,1136
9
+ paddle/plot_cubed_sphere_panel.py,sha256=jK813orIrRHjvZ5WwX3gzAZ1cub8eQFRTqU8cXtU5VM,525
10
+ paddle/pt2nc.py,sha256=lLviBm6a2O05RvuPQc8DxV5pGr_VEhlSkrKPV1lQ3yU,3913
11
+ paddle/setup_profile.py,sha256=A4ityv7RKeOyAEcsGKewxI_VHFeJ3mMGgqrxKnBCkMk,8869
12
+ paddle/write_profile.py,sha256=TFpRvh0OKDIuDfiUqvxrI53AokAkkiVjTtXWXNtXTzU,3912
13
+ paddle-1.2.1.dist-info/METADATA,sha256=JB4fFHByrqbHgFqr0bvdwbVgGTaQ1na0mh7hx_rw_3g,6005
14
+ paddle-1.2.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
15
+ paddle-1.2.1.dist-info/entry_points.txt,sha256=pDR96GW6ylBZrbFd-tRGthW8qTuYaSLjrEt1LFIEYto,48
16
+ paddle-1.2.1.dist-info/licenses/LICENSE,sha256=e6NthgKABUnLRqjuETcBGgsOuA-aJANpNoeXMe9RBso,1071
17
+ paddle-1.2.1.dist-info/RECORD,,
@@ -1,14 +0,0 @@
1
- paddle/__init__.py,sha256=RAXFapvqRTn4YjzlDkCj3POZcN3LP43d14YabPEdjzE,281
2
- paddle/crm.py,sha256=pME4nF5gjlJm-36yMl0N8bzT6UBr2CsOD6nopby7e9M,1993
3
- paddle/evolve_kinetics.py,sha256=3fkFnYqJRNimOaxuf2FAnMUrMGaaP1vJwSWfRU3R1XM,1553
4
- paddle/example_save.py,sha256=MYVOr9J5oTU2NILPnr3qhHdbU7u81Rtca8RjVv8xE6s,610
5
- paddle/find_init_params.py,sha256=EwedId1KljMxOD0lD7RZmWJGJuaItiPPlW_EtW8O6L8,2528
6
- paddle/nc2pt.py,sha256=LXR0fnUTaOA_uaDsLU4YqdAVFyycB6SvRq12xWhHhLA,1136
7
- paddle/pt2nc.py,sha256=lLviBm6a2O05RvuPQc8DxV5pGr_VEhlSkrKPV1lQ3yU,3913
8
- paddle/setup_profile.py,sha256=GkeucqDZvi3ZW5uTf4Y8fMaPe1XGQu1Mhg2NJkO6uD0,8770
9
- paddle/write_profile.py,sha256=g2e7RIViwiEok0fbfgDgait2dVVYSdzUcu8WGd5sD9g,3914
10
- paddle-1.2.0.dist-info/METADATA,sha256=9Ae-55Z2CMkb6ymoTVzVXms2_Gq0n1yetcwppi-b2qA,6005
11
- paddle-1.2.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
12
- paddle-1.2.0.dist-info/entry_points.txt,sha256=pDR96GW6ylBZrbFd-tRGthW8qTuYaSLjrEt1LFIEYto,48
13
- paddle-1.2.0.dist-info/licenses/LICENSE,sha256=e6NthgKABUnLRqjuETcBGgsOuA-aJANpNoeXMe9RBso,1071
14
- paddle-1.2.0.dist-info/RECORD,,
File without changes