Skip to content

Commit 68f2e56

Browse files
authored
Merge pull request #236 from svalinn/nwl-ref_surf
Enable use of rib-based surfaces in NWL workflow
2 parents f80130e + baa1571 commit 68f2e56

File tree

5 files changed

+14829
-8293
lines changed

5 files changed

+14829
-8293
lines changed

parastell/nwl_utils.py

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import math
2-
from pathlib import Path
2+
from pathlib import Path, PosixPath
33
import concurrent.futures
44
import os
55
import sys
@@ -12,6 +12,7 @@
1212
from pystell import read_vmec
1313
import matplotlib.pyplot as plt
1414

15+
from . import invessel_build
1516
from . import log
1617
from .utils import m2cm
1718

@@ -90,12 +91,12 @@ def fire_rays(dagmc_geom, source_mesh, toroidal_extent, strengths, num_parts):
9091
return "surface_source.h5"
9192

9293

93-
def compute_residual(poloidal_guess, vmec_obj, wall_s, toroidal_angle, point):
94+
def compute_residual(poloidal_guess, ref_surf, wall_s, toroidal_angle, point):
9495
"""Minimization problem to solve for the poloidal angle.
9596
9697
Arguments:
9798
poloidal_guess (float): poloidal angle guess [rad].
98-
vmec_obj (object): plasma equilibrium VMEC object.
99+
ref_surf (object): ReferenceSurface object.
99100
wall_s (float): closed flux surface label extrapolation at wall.
100101
toroidal_angle (float): toroidal angle [rad].
101102
point (numpy.array): Cartesian coordinates [cm].
@@ -104,9 +105,8 @@ def compute_residual(poloidal_guess, vmec_obj, wall_s, toroidal_angle, point):
104105
(float): L2 norm of difference between coordinates of interest and
105106
computed point [cm].
106107
"""
107-
fw_guess = (
108-
np.array(vmec_obj.vmec2xyz(wall_s, poloidal_guess, toroidal_angle))
109-
* m2cm
108+
fw_guess = np.array(
109+
ref_surf.angles_to_xyz(toroidal_angle, poloidal_guess, wall_s, m2cm)[0]
110110
)
111111

112112
return np.linalg.norm(point - fw_guess)
@@ -119,9 +119,8 @@ def solve_poloidal_angles(data):
119119
120120
Arguments:
121121
data (iterable): data for root-finding algorithm. Entries in order:
122-
1) path to plasma equilibrium VMEC file (str). Because the VMEC
123-
dataset is not picklable, a separate object is created for each
124-
thread.
122+
1) path to plasma equilibrium VMEC file (str) or ReferenceSurface
123+
object (object).
125124
2) first wall CFS reference value (float).
126125
3) convergence tolerance for root-finding (float).
127126
4) toroidal angles at which to solve for poloidal angles
@@ -133,7 +132,12 @@ def solve_poloidal_angles(data):
133132
poloidal_angles (list): poloidal angles corresponding to supplied
134133
coordinates [rad].
135134
"""
136-
vmec_obj = read_vmec.VMECData(data[0])
135+
if isinstance(data[0], (str, PosixPath)):
136+
vmec_obj = read_vmec.VMECData(data[0])
137+
ref_surf = invessel_build.VMECSurface(vmec_obj)
138+
else:
139+
ref_surf = data[0]
140+
137141
wall_s = data[1]
138142
conv_tol = data[2]
139143
toroidal_angles = data[3]
@@ -145,19 +149,20 @@ def solve_poloidal_angles(data):
145149
result = direct(
146150
compute_residual,
147151
bounds=[(0, 2 * np.pi)],
148-
args=(vmec_obj, wall_s, toroidal_angle, point),
152+
args=(ref_surf, wall_s, toroidal_angle, point),
149153
vol_tol=conv_tol,
150154
)
151155
poloidal_angles.append(result.x[0])
152156

153157
return poloidal_angles
154158

155159

156-
def compute_flux_coordinates(vmec_file, wall_s, coords, num_threads, conv_tol):
160+
def compute_flux_coordinates(ref_surf, wall_s, coords, num_threads, conv_tol):
157161
"""Computes flux coordinates of specified Cartesian coordinates.
158162
159163
Arguments:
160-
vmec_file (str): path to plasma equilibrium VMEC file.
164+
ref_surf: path to plasma equilibrium VMEC file (str) or ReferenceSurface
165+
object (object).
161166
wall_s (float): closed flux surface extrapolation at first wall.
162167
coords (numpy.array): Cartesian coordinates of surface crossings [cm].
163168
conv_tol (float): convergence tolerance for root-finding.
@@ -174,7 +179,7 @@ def compute_flux_coordinates(vmec_file, wall_s, coords, num_threads, conv_tol):
174179
for chunk_start in range(0, len(toroidal_angles), chunk_size):
175180
chunks.append(
176181
(
177-
vmec_file,
182+
ref_surf,
178183
wall_s,
179184
conv_tol,
180185
toroidal_angles[chunk_start : chunk_start + chunk_size],
@@ -247,7 +252,7 @@ def compute_quadrilateral_area(corners):
247252

248253
def compute_nwl(
249254
source_file,
250-
vmec_file,
255+
ref_surf,
251256
wall_s,
252257
toroidal_extent,
253258
neutron_power,
@@ -263,7 +268,12 @@ def compute_nwl(
263268
264269
Arguments:
265270
source_file (str): path to OpenMC surface source file.
266-
vmec_file (str): path to plasma equilibrium VMEC file.
271+
ref_surf (object): path to plasma equilibrium VMEC file (str) or
272+
ReferenceSurface object (object). If ReferenceSurface, must have a
273+
method 'angles_to_xyz(toroidal_angles, poloidal_angles, s, scale)'
274+
that returns an Nx3 numpy array of cartesian coordinates for any
275+
closed flux surface label, s, poloidal angle, and toroidal angle.
276+
Cannot be VMECSurface object, since those are not picklable.
267277
wall_s (float): closed flux surface label extrapolation at wall.
268278
toroidal_extent (float): toroidal extent of model [deg].
269279
neutron_power (float): reference neutron power [MW].
@@ -315,7 +325,7 @@ def compute_nwl(
315325
logger.info(f"Processing batch {batch_num}")
316326

317327
toroidal_angle_batch, poloidal_angle_batch = compute_flux_coordinates(
318-
vmec_file,
328+
ref_surf,
319329
wall_s,
320330
coords[batch_start : batch_start + batch_size],
321331
num_threads,
@@ -362,13 +372,16 @@ def compute_nwl(
362372

363373
nwl_mat = count_mat * neutron_power / num_particles
364374

375+
if isinstance(ref_surf, (str, PosixPath)):
376+
vmec_obj = read_vmec.VMECData(ref_surf)
377+
ref_surf = invessel_build.VMECSurface(vmec_obj)
378+
365379
# Construct matrix of bin boundaries
366-
vmec_obj = read_vmec.VMECData(vmec_file)
367380
bin_mat = np.zeros((num_toroidal_bins + 1, num_poloidal_bins + 1, 3))
368381
for toroidal_id, toroidal_edge in enumerate(toroidal_bin_edges):
369-
for poloidal_id, poloidal_edge in enumerate(poloidal_bin_edges):
370-
x, y, z = vmec_obj.vmec2xyz(wall_s, poloidal_edge, toroidal_edge)
371-
bin_mat[toroidal_id, poloidal_id, :] = [x, y, z]
382+
bin_mat[toroidal_id, :, :] = ref_surf.angles_to_xyz(
383+
toroidal_edge, poloidal_bin_edges, wall_s, m2cm
384+
)
372385

373386
# Construct matrix of bin areas
374387
area_mat = np.zeros((num_toroidal_bins, num_poloidal_bins))

0 commit comments

Comments
 (0)