gvec.util#
GVEC utility module
This module is part of the gvec python package, but also used directly in the tests.
- class gvec.util.CaseInsensitiveDict(data=(), /, **kwargs)#
Bases:
MutableMappingA dictionary-like Mutable Mapping where string keys are case-insensitive.
Implements all methods and operations of
MutableMappingas well as dict’scopy. Also provideslower_itemsandlower_keys.Keys that are not strings will be stored as-is. The structure remembers the case of the last used key, and
iter(instance),keys(),items(),iterkeys(), anditeritems()will contain case-sensitive keys. However, querying and contains testing is case insensitive.- Raises:
ValueError – If the constructor,
.update, or equality comparison operations are given keys that have equal.lower()representations. This is to avoid ambiguity in lookups and ensure consistent behavior.
Examples
>>> cid = CaseInsensitiveDict() >>> cid['param'] = 'value' >>> cid['Param'] == 'value' True
- copy()#
Return a deep copy.
- lower_items()#
- lower_keys()#
- serialize()#
Recursively serialize this object, converting Mappings to dicts and Iterables to lists.
- update([E, ]**F) None. Update D from mapping/iterable E and F.#
If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k, v in F.items(): D[k] = v
- gvec.util.adapt_parameter_file(source: str | Path, target: str | Path, **kwargs)#
Copy the source file to the target file and replace the parameters according to
kwargs.- Parameters:
source (str or Path) – The path to the source parameter file.
target (str or Path) – The path to the target parameter file.
**kwargs – Keyword arguments representing the parameters to be replaced. if the value of the key is “!”, the line with the keyword is uncommented, if possible
- Raises:
AssertionError – If the number of occurrences for any parameter is not exactly 1.
Notes
If no parameters are provided in
kwargs, the function simply copies thesourcefile to thetargetfile.The function replaces the parameters in the format
key = value, where value is either a sequence of characters containing no whitespace or a single pair of parentheses with any content. The value fromkwargsis inserted using the standard python string conversion. There may be a comment, starting with!, after the value.If a parameter already exists in the
sourcefile, its value is replaced with the corresponding value fromkwargs.If a parameter does not exist in the
sourcefile, it is added to thetargetfile.If the value of the key starts with “!”, the line with the keyword is just uncommented. (i.e.
"!key=2.5" -> "key=2.5") If no line with the keyword is found, the key is added with the value, excluding the leading"!"(i.e. value is"!0.5" -> "key=0.5"is added)
Example
adapt_parameter_file('/path/to/source.ini', '/path/to/target.ini', param1=1.2, param2="(1, 2, 3)")
- gvec.util.axis_from_boundary(parameters: MutableMapping) MutableMapping#
- gvec.util.boundary_generator(case: str, X1_00=1.0, a0=0.5, ellipticity=0.4, helix_r=0.5)#
Define parameters for some simple boundaries for testing.
- Parameters:
case (str) –
- The name of the boundary:
see boundary_generator_cases dictionary
X1_00 (float, optional) – =major radius if \(X^1=R\)
a0 (float, optional) – =minor radius scale
ellipticity (float, optional) – =ellipticity of the cross section
- Return type:
parameter dictionary describing
- gvec.util.boundary_generator_cases()#
- gvec.util.bspl2gvec(name: Literal['iota', 'pres'], bspl: BSpline | None = None, knots: _Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None = None, coefs: _Buffer | _SupportsArray[dtype[Any]] | _NestedSequence[_SupportsArray[dtype[Any]]] | bool | int | float | complex | str | bytes | _NestedSequence[bool | int | float | complex | str | bytes] | None = None, params: dict = {}) dict#
Translates a scipy B-spline object or B-spline coefficients and knots for either a iota or pressure profile into a dictionary entries that can be handed to adapt_parameter_file.
- Parameters:
name (str) – profile identifyer, has to be either iota or pres.
bspl (scipy.interpolate.BSpline) – scipy BSpline object. If this is not provided knots and coefs are expected.
knots (ArrayLike) – Knots for the B-splines. Note that repeated edge knots according to the degree are expected.
coefs (ArrayLike) – Coefficients for the B-splines.
params (dict, optional) – Dictionary of gvec input parameters that will be adapted. Defaults to {}.
- Raises:
ValueError – If name is neither iota nor pres.
TypeError – If neither bspl nor knots and coefs is provided.
- Returns:
Dictionary of gvec input parameters
- Return type:
dict
- gvec.util.chdir(target: Path | str)#
Contextmanager to change the current working directory.
Using a context has the benefit of automatically changing back to the original directory when the context is exited, even if an exception is raised.
- gvec.util.check_boundary_direction(parameters: Mapping) bool#
Determine whether the boundary is described by right-handed logical coordinates (θ,ζ).
GVEC requires a right-handed logical coordinate system (ρ,θ,ζ). The logical coordinate system of the poloidal plane, (ρ,θ) is also required to be right-handed, which requires the poloidal angle to increase in the counter-clockwise direction. As a consequence the toroidal angle has to increase in the clockwise direction when viewed from above. This is ensured in the definition of the h-maps.
- Returns:
True if (ρ,θ) is right-handed / θ increases counter-clockwise, False otherwise.
- Return type:
bool
- gvec.util.compute_FD(f: ndarray, pos, coefs, axis=0)#
1D Finite difference of a function f on equispaced n-dimnesional grid, using FD coefficients coefficients
coefsand relative integer positions to the central evaluation pointpos, along one given axis.Warning
if data is periodic, meaning that endpoints of periodic interval are excluded, result can be on all points.
If data is not periodic, the result at the boundaries is WRONG, for the points
|min(pos)|on the left andmax(pos)on the right along the given axis.
- Parameters:
f (numpy.ndarray) – function values on equispaced n-dimnesional grid
pos (int) – relative integer positions to the central evaluation point, as 1d list or 1d array of integers
coefs (float) – FD coefficients for each position, as 1d list or 1d array, same size as pos!
axis (int, optional) – axis along which the FD is computed, default is 0
- Returns:
df – Finite-Difference result, same shape as f (see warning above!)
- Return type:
numpy.ndarray
Examples
- examples for first derivative of f:
1st order forward FD:
pos=[1,0]; coefs=[-1,1]/(dx)2nd order central FD:
pos=[-1,1]; coefs=[-1,1]/(2*dx)4th order central FD:
pos=[-2,-1,1,2]; coefs=[1/12,-2/3,2/3,-1/12]/(dx)6th order central FD:
pos=[-3,-2,-1,1,2,3]; coefs=[-1/60,3/20,-3/4,3/4,-3/20,1/60]/(dx)8th order central FD:
pos=[-4,-3,-2,-1,1,2,3,4]; coefs=[1/280,-4/105,1/5,-4/5,4/5,-1/5,4/105,-1/280]/(dx)
- examples for second derivatives of f:
2nd order central FD:
pos=[-1,0,1]; coefs=[1,-2,1]/(dx**2)4th order central FD:
pos=[-2,-1,1,2]; coefs=[-1/12, 4/3,-5/2, 4/3,-1/12]/(dx**2)6th order central FD:
pos=[-3,-2,-1,1,2,3]; coefs=[1/90,-3/20,3/2,-49/18,3/2,-3/20,1/90]/(dx**2)8th order central FD:
pos=[-4,-3,-2,-1,1,2,3,4]; coefs=[-1/560,8/315,-1/5,8/5,-205/72,8/5,-1/5,8/315,-1/560]/(dx**2)
- gvec.util.compute_boundary_perturbation(base_parameters: Mapping, perturbed_parameters: Mapping) tuple[CaseInsensitiveDict, CaseInsensitiveDict]#
Computes the difference between the perturbed and base boundary parameters as a perturbation.
- gvec.util.effective_minor_radius(parameters: Mapping, resolution: tuple[int, int] = (1000, 100))#
- gvec.util.ellipse_circumference_factor(epsilon: float) float#
Compute the circumference factor of an ellipse with elongation epsilon. This uses the approximation by Ramanujan, accurate up to h^5 (6.5% error at ε=10).
A = a b π = aeff^2 π ε = a / b >= 1 C = 2 π aeff Cf(ε) Cf ~ (1 + ε) / (2 √ε) [1 + 3 h / (10 + √(4 - 3 h))] h = (ε - 1)^2 / (ε + 1)^2
- gvec.util.evaluate_axis(zeta: ndarray, parameters: Mapping) tuple[ndarray, ndarray]#
Evaluate the magnetic axis at the given zeta points.
- Parameters:
zeta (1D np.ndarray) – The toroidal angles at which to evaluate the axis.
parameters (Mapping) – The parameters defining the axis.
- Returns:
The (X^1, X^2) coordinates of the axis at the given zeta points.
- Return type:
tuple[1D np.ndarray, 1D np.ndarray]
- gvec.util.evaluate_boundary(theta: ndarray, zeta: ndarray, parameters: Mapping) tuple[ndarray, ndarray]#
Evaluate the boundary at the given (theta, zeta) points.
- Parameters:
theta (1D np.ndarray) – The poloidal angles at which to evaluate the boundary.
zeta (1D np.ndarray) – The toroidal angles at which to evaluate the boundary.
parameters (Mapping) – The parameters defining the boundary.
- Returns:
The (X^1, X^2) coordinates of the boundary at the given (theta, zeta) points.
- Return type:
tuple[2D np.ndarray, 2D np.ndarray]
- gvec.util.flatten_parameters(parameters: Mapping) CaseInsensitiveDict#
Flatten parameters from a hierarchical dictionary
- gvec.util.flip_boundary_theta(parameters: MutableMapping) MutableMapping#
Flip the boundary parameters in the poloidal direction. θ → -θ.
- gvec.util.flip_boundary_zeta(parameters: MutableMapping) MutableMapping#
- gvec.util.flip_parameters_theta(parameters: MutableMapping) MutableMapping#
- gvec.util.flip_parameters_zeta(parameters: MutableMapping) MutableMapping#
- gvec.util.get_compile_options() str#
- gvec.util.linking_number(curve_a: ndarray, curve_b: ndarray, tol=1e-15, endpoint=False)#
Compute the linking number of two non-intersecting curves \(C_a(\zeta_a),C_b(\zeta_b)\), solving the (non-singular) double integral over two curves
\[ \text{Lk} = \frac{1}{4\pi}\int_0^{2\pi} \int_0^{2\pi} \frac{ r_b - r_a}{\abs{r_b - r_a}^3} \cdot \left(\frac{\partial r_a}{\partial\zeta_a} \times \frac{\partial r_b}{\partial\zeta_b}\right) d{\zeta_a} d{\zeta_b} \]Here, the double integral is approximated by representing the curves as polygons, and computing the linking number as the sum of solid angles between all linear segments of polygon curves. The solid angle of two linear segments can be computed exactly. See paper by [Klenin and Langowski](https://onlinelibrary.wiley.com/doi/10.1002/1097-0282(20001015)54:5%3C307::AID-BIP20%3E3.0.CO;2-Y) See GVEC documentation for more details.
- Parameters:
curve_a (np.ndarray) – the x,y,z point positions of the first curve. First and last point must coincide, if endpoint=True. shape must be [npoints_a,3]
curve_b (np.ndarray) – the x,y,z point positions of the first curve. First and last point must coincide, if endpoint=True. shape must be [npoints_b,3]
tol (float) – tolerance to consider points coincident (default: 1e-15)
endpoint (bool) – True: the first and last point of each curve coincide, else the last point is connected to the first point to close the curve. Default is False.
- Returns:
Lk – the linking number of the two curves
- Return type:
float
- gvec.util.logging_setup()#
Setup default logging configuration for GVEC.
- gvec.util.parameters_from_vmec(nml: Mapping, name: str) CaseInsensitiveDict#
- gvec.util.read_parameter_file_ini(path: str | Path) CaseInsensitiveDict#
Read the parameters from the specified parameter file in GVEC-ini format.
- Parameters:
path (str | Path) – The path to the parameter file.
- Returns:
A mapping (with case insensitive keys) containing the parameters from the parameter file.
- Return type:
Example: >>> read_parameter_file_ini(‘/path/to/parameter.ini’) {‘param1’: 1.2, ‘param2’: (1, 2, 3), ‘param3’: {(-1, 0): 0.5, (0, 0): 1.0}}
- gvec.util.read_parameters(path: Path | str, format: Literal['ini', 'yaml', 'toml'] | None = None) CaseInsensitiveDict#
- gvec.util.shift_boundary_theta_pi(parameters: MutableMapping) MutableMapping#
Shift the theta origin of the boundary by pi.
cos(m(θ+π)-nζ) = (-1)^m cos(mθ-nζ) sin(m(θ+π)-nζ) = (-1)^m sin(mθ-nζ)
- gvec.util.signed_cross_sectional_area(parameters: Mapping, zeta: float, resolution: int = 1000) float#
- gvec.util.solid_angle_between_segments(r1: ndarray, r2: ndarray, r3: ndarray, r4: ndarray, tol=1e-15)#
Compute the solid angle between two line segments r1->r2 and r3->r4. See paper by [Klenin and Langowski](https://onlinelibrary.wiley.com/doi/10.1002/1097-0282(20001015)54:5%3C307::AID-BIP20%3E3.0.CO;2-Y) and direct summation from https://doi.org/10.1145/3450626.3459778 r1,r2,r3,r4 must have the same shape, with last dimension of size 3 (x,y,z) :param r1: last dimension is x,y,z position of the first point of the first segment :type r1: np.ndarray :param r2: last dimension is x,y,z position of the second point of the first segment :type r2: np.ndarray :param r3: last dimension is x,y,z position of the first point of the second segment :type r3: np.ndarray :param r4: last dimension is x,y,z position of the second point of the second segment :type r4: np.ndarray :param tol: tolerance to consider points coincident (default: 1e-15) :type tol: float
- Returns:
solid angle between the two segments, without 1/(4pi) factor
- Return type:
omega (float)
- gvec.util.stack_parameters(parameters: Mapping) CaseInsensitiveDict#
Stack parameters into a hierarchical dictionary
- gvec.util.stringify_mn_parameters(parameters: Mapping) CaseInsensitiveDict#
Serialize parameters into a string
- gvec.util.unstringify_mn_parameters(parameters: Mapping) CaseInsensitiveDict#
Deserialize parameters from a string
- gvec.util.version_info() str#
- gvec.util.write_parameter_file_ini(parameters: Mapping, path: str | Path = 'parameter.ini', header: str = '')#
Write the parameters to the specified parameter file in GVEC-ini format.
- Parameters:
parameters – A mapping containing the parameters to be written to the parameter file.
path – The path to the parameter file.
- gvec.util.write_parameters(parameters: Mapping, path: Path | str = 'parameter.ini', format: Literal['ini', 'yaml', 'toml'] | None = None)#
- gvec.util.writhe_from_polygon(curve: ndarray, endpoint=False)#
Compute the writhe of a closed curve \(C(\zeta)\), solving the (singular!) double integral over the curve
\[ \text{Wr} = \frac{1}{4\pi}\int_0^{2\pi} \int_0^{2\pi} \frac{ r(\zeta^\prime) - r(\zeta)}{\abs{r(\zeta^\prime) - r(\zeta)}^3} \cdot \left(\frac{\partial r}{\partial\zeta} \times \frac{\partial r}{\partial\zeta^\prime} \right) d{\zeta} d{\zeta^\prime} \]Here, the double integral is approximated by representing the curve as a polygon, and computing the writhe as the sum of solid angles between all linear segments of polygon curve. The solid angle of two linear segments can be computed exactly. See paper by [Klenin and Langowski](https://onlinelibrary.wiley.com/doi/10.1002/1097-0282(20001015)54:5%3C307::AID-BIP20%3E3.0.CO;2-Y) See GVEC documentation for more details.
- Parameters:
curve (np.ndarray) – the x,y,z point positions of the curve. First and last point must coincide, if endpoint=True. shape must be [npoints,3]
endpoint (bool) – True: the first and last point of the curve coincide, else the last point is connected to the first point to close the curve. Default is False
- Returns:
Wr – the approximate writhe of the curve
- Return type:
float
Warning
The algorithm converges very slowly with the number of line segments.