Source code for boutpy.boutdata.gen_surface

# Flux surface generator for tokamak grid files

__all__ = ['gen_surface']

import numpy as np


[docs]def gen_surface(grid): """Generator of flux surface indices""" # Read the grid data nx = grid.read("nx") ny = grid.read("ny") npol = grid.read("npol") if npol is None: # Domains not stored in file (BOUT style input) ixseps1 = grid.read("ixseps1") ixseps2 = grid.read("ixseps2") jyseps1_1 = grid.read("jyseps1_1") jyseps2_2 = grid.read("jyseps2_2") if ixseps1 == ixseps2: # Single null ndomains = 3 else: # Double null ndomains = 6 yup_xsplit = np.zeros(ndomains) ydown_xsplit = np.zeros(ndomains) yup_xin = np.zeros(ndomains) yup_xout = np.zeros(ndomains) ydown_xin = np.zeros(ndomains) ydown_xout = np.zeros(ndomains) ystart = np.zeros(ndomains + 1) ystart[ndomains] = ny # Inner lower leg ydown_xsplit[0] = -1 ydown_xout[0] = -1 yup_xsplit[0] = ixseps1 yup_xin[0] = ndomains - 1 # Outer lower leg yup_xout[0] = 1 # Outer lower leg ydown_xsplit[ndomains - 1] = ixseps1 ydown_xin[ndomains - 1] = 0 ydown_xout[ndomains - 1] = ndomains - 2 yup_xsplit[ndomains - 1] = -1 yup_xout[ndomains - 1] = -1 ystart[ndomains - 1] = jyseps2_2 + 1 if ixseps1 == ixseps2: # Single null ydown_xsplit[1] = ixseps1 ydown_xin[1] = 1 ydown_xout[1] = 0 yup_xsplit[1] = ixseps1 yup_xin[1] = 1 yup_xout[1] = 2 ystart[1] = jyseps1_1 + 1 else: # Double null raise "SORRY - NO DOUBLE NULL YET" else: # Use domains stored in the file ndomains = npol.size # Number of domains yup_xsplit = grid.read("yup_xsplit") ydown_xsplit = grid.read("ydown_xsplit") yup_xin = grid.read("yup_xin") yup_xout = grid.read("yup_xout") ydown_xin = grid.read("ydown_xin") ydown_xout = grid.read("ydown_xout") # Calculate starting positions ystart = np.zeros(ndomains + 1) for i in np.arange(1, ndomains): ystart[i] = ystart[i - 1] + npol[i - 1] ystart[ndomains] = ny # Record whether a domain has been visited visited = np.zeros(ndomains) x = 0 # X index while True: yinds = None # Y indices result # Find a domain which hasn't been visited domain = None for i in np.arange(ndomains): if visited[i] == 0: domain = i break if domain is None: # All domains visited x = x + 1 # Go to next x surface visited = np.zeros(ndomains) # Clear the visited array if x == nx: break # Finished continue # Follow surface back until it hits a boundary while True: if x < ydown_xsplit[domain]: d = ydown_xin[domain] else: d = ydown_xout[domain] if d < 0: break # Hit boundary domain = d # Keep going # Starting from domain, follow surface periodic = False while domain >= 0: if visited[domain] == 1: # Already visited domain -> periodic periodic = True break # Get range of y indices in this domain yi = np.arange(ystart[domain], ystart[domain + 1]) if yinds is None: yinds = yi else: yinds = np.concatenate((yinds, yi)) # mark this domain as visited visited[domain] = 1 # Get next domain if x < yup_xsplit[domain]: domain = yup_xin[domain] else: domain = yup_xout[domain] # Finished this surface yield x, yinds, periodic