scripts/gray_visual.py: rewrite and extend scope
This commit is contained in:
parent
24e0e6e472
commit
864cf23b78
115
scripts/gray.py
Normal file
115
scripts/gray.py
Normal file
@ -0,0 +1,115 @@
|
||||
'''
|
||||
Python interface for GRAY
|
||||
'''
|
||||
|
||||
# output files handling
|
||||
import numpy as np
|
||||
import collections
|
||||
import io
|
||||
from configparser import ConfigParser
|
||||
|
||||
# standard GRAY simulation
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
# Type of a parsed EQDSK file
|
||||
Eqdsk = collections.namedtuple('Eqdsk', ['flux', 'boundary', 'limiter', 'q'])
|
||||
|
||||
|
||||
def read_eqdsk(filepath: Path) -> Eqdsk:
|
||||
'''
|
||||
Loads a full G-EQDSK file and returns:
|
||||
R, z, ψ(R, z), q(ρ)
|
||||
'''
|
||||
def read(file, n):
|
||||
'''
|
||||
Reads n records of a G-EQDSK file
|
||||
'''
|
||||
x = np.empty(n)
|
||||
for i in range(n):
|
||||
x[i] = float(file.read(16).strip())
|
||||
return x
|
||||
|
||||
def skip(file, n):
|
||||
'''
|
||||
Skip n records of a G-EQDSK file
|
||||
'''
|
||||
file.seek(file.tell() + 16 * n)
|
||||
|
||||
with open(filepath) as file:
|
||||
file = io.StringIO(''.join(file.read().splitlines()))
|
||||
|
||||
# comment string
|
||||
file.read(48)
|
||||
|
||||
# number of (R, z) grid points
|
||||
_, nr, nz = [int(i) for i in file.read(4 * 3).split()]
|
||||
|
||||
# build (R, z) grid
|
||||
r_dim, z_dim, _, r_left, z_mid = read(file, 5)
|
||||
r = np.linspace(r_left, r_left + r_dim, nr)
|
||||
z = np.linspace(z_mid - z_dim/2, z_mid + z_dim/2, nz)
|
||||
|
||||
# ψ on the axis/boundary
|
||||
psi_min, psi_max = read(file, 5)[2:4]
|
||||
|
||||
# skip other MHD quantities
|
||||
skip(file, 5 * 2)
|
||||
skip(file, nr * 4)
|
||||
|
||||
# read flux and safety factor
|
||||
psi = read(file, nr * nz).reshape(nr, nz)
|
||||
q = read(file, nr)
|
||||
|
||||
# normalise flux
|
||||
psi = abs(psi - psi_min) / abs(psi_max - psi_min)
|
||||
|
||||
# plasma boundary and limiter contour
|
||||
nbound, nlim = [int(i) for i in file.read(5 * 2).split()]
|
||||
rbound, zbound = read(file, nbound * 2).reshape(nbound, 2).T
|
||||
rlim, zlim = read(file, nlim * 2).reshape(nlim, 2).T
|
||||
|
||||
return Eqdsk(flux=(r, z, psi),
|
||||
boundary=(rbound, zbound),
|
||||
limiter=(rlim, zlim),
|
||||
q=(np.sqrt(np.linspace(0, 1, nr)), abs(q)))
|
||||
|
||||
|
||||
def read_conf(fname: Path):
|
||||
'''
|
||||
Parses gray.ini configuration file
|
||||
'''
|
||||
config = ConfigParser()
|
||||
with open(fname) as ini:
|
||||
config.read_file(ini)
|
||||
return config
|
||||
|
||||
|
||||
def read_table(fname: Path):
|
||||
'''
|
||||
Loads a GRAY output unit file as a structured numpy array
|
||||
'''
|
||||
return np.genfromtxt(fname, skip_header=21, names=True)
|
||||
|
||||
|
||||
def get_limiter(conf: ConfigParser, inputs: Path) -> np.array:
|
||||
'''
|
||||
Returns the limiter contour
|
||||
'''
|
||||
file = conf['equilibrium']['filenm'].strip('"')
|
||||
|
||||
if conf['equilibrium'].get('iequil') == 'EQ_ANALYTICAL':
|
||||
return np.loadtxt(inputs / file, skiprows=4).T
|
||||
else:
|
||||
eqdsk = read_eqdsk(inputs / file)
|
||||
return eqdsk.limiter
|
||||
|
||||
|
||||
def decode_index_rt(i: int) -> (str, int):
|
||||
'''
|
||||
Given the index_rt of a beam, returns the polarisation
|
||||
mode ('O' or 'X') and the number of passes
|
||||
'''
|
||||
mode = ['X', 'O'][i % 2]
|
||||
passes = int(np.floor(np.log2(1 + i)))
|
||||
return mode, passes
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user