import numpy as np
from .._io.input._helpers import read
from ._cylindric_grid import cylindric_grid
from ._structured_grid import structured_grid
[docs]
def from_meshmaker(filename_or_dict, material="dfalt"):
"""
Generate a mesh from a block MESHM.
Parameters
----------
filename_or_dict: str, pathlike, buffer or dict
Input file name, buffer or parameters dict with key "meshmaker".
material : str, optional, default 'dfalt'
Default material name.
"""
if isinstance(filename_or_dict, str):
parameters = read(filename_or_dict, file_format="tough")
else:
parameters = filename_or_dict
if "meshmaker" not in parameters:
raise ValueError()
if "type" not in parameters["meshmaker"]:
raise ValueError()
if parameters["meshmaker"]["type"] not in {"xyz", "rz2d", "rz2dl"}:
raise ValueError()
# XYZ
if parameters["meshmaker"]["type"] == "xyz":
dx_, dy_, dz_ = parse_xyz(parameters["meshmaker"]["parameters"])
dx, dy, dz = [], [], []
for increment in dx_:
append(dx, **increment)
for increment in dy_:
append(dy, **increment)
for increment in dz_:
append(dz, **increment)
if not len(dx):
dx = [1.0]
if not len(dy):
dy = [1.0]
if not len(dz):
dz = [1.0]
return structured_grid(dx, dy, dz, material=material)
# RZ2D
else:
dr_, dz_ = parse_rz2d(parameters["meshmaker"]["parameters"])
dr, dz = [], []
for increment in dr_:
append(dr, **increment)
for increment in dz_:
append(dz, **increment)
if not len(dr):
dr = [1.0]
if not len(dz):
dz = [1.0]
return cylindric_grid(
dr, dz, layer=parameters["meshmaker"]["type"] == "rz2dl", material=material
)
def parse_xyz(parameters):
"""Parse input for XYZ mesh."""
def parse(parameter):
n = get_value(parameter, "n_increment", 1)
if n <= 0:
raise ValueError()
sizes = get_value(parameter, "sizes", 0.0)
if np.ndim(sizes) == 0:
if sizes < 0.0:
raise ValueError()
tmp = [
{
"n_increment": n,
"size": sizes,
"type": "uniform",
"radius_ref": None,
}
]
elif np.ndim(sizes) == 1:
if (np.array(sizes) < 0.0).any():
raise ValueError()
tmp = [
{
"n_increment": count,
"size": value,
"type": "uniform",
"radius_ref": None,
}
for count, value in zip(*squeeze(sizes))
]
return tmp
dx, dy, dz = [], [], []
for parameter in parameters:
if parameter["type"] == "nx":
dx += parse(parameter)
elif parameter["type"] == "ny":
dy += parse(parameter)
elif parameter["type"] == "nz":
dz += parse(parameter)
return dx, dy, dz
def parse_rz2d(parameters):
"""Parse input for RZ2D mesh."""
rmax = 0.0
dr, dz = [], []
for parameter in parameters:
if parameter["type"] == "radii":
if len(parameter["radii"]) < 2:
continue
tmp = np.diff(parameter["radii"])
if (tmp < 0.0).any():
raise ValueError("radii must be sorted in ascending order.")
rmax += tmp.sum()
dr += [
{
"n_increment": count,
"size": value,
"type": "uniform",
"radius_ref": None,
}
for count, value in zip(*squeeze(tmp))
]
elif parameter["type"] == "equid":
n = get_value(parameter, "n_increment", 1)
if n <= 0:
raise ValueError()
size = get_value(parameter, "size", 0.0)
if size < 0.0:
raise ValueError()
rmax += n * size
dr.append(
{
"n_increment": n,
"size": size,
"type": "uniform",
"radius_ref": None,
}
)
elif parameter["type"] == "logar":
n = get_value(parameter, "n_increment", 1)
if n <= 0:
raise ValueError()
radius = get_value(parameter, "radius", 0.0)
if radius <= rmax:
raise ValueError()
else:
size = radius - rmax
radius_ref = get_value(parameter, "radius_ref", 0.0)
if radius_ref < 0.0:
raise ValueError()
rmax += size
dr.append(
{
"n_increment": n,
"size": size,
"type": "logarithmic",
"radius_ref": radius_ref,
}
)
elif parameter["type"] == "layer":
dz += [
{
"n_increment": count,
"size": value,
"type": "uniform",
"radius_ref": None,
}
for count, value in zip(*squeeze(parameter["thicknesses"]))
]
return dr, dz
def get_value(parameter, key, default):
"""Helper function to get value in dictionary."""
return (
default
if key not in parameter
or (isinstance(parameter[key], list) and not len(parameter[key]))
or parameter[key] is None
else parameter[key]
)
def squeeze(data):
"""Squeeze a sequence."""
count = [1]
values = [data[0]]
for value in data[1:]:
if value == values[-1]:
count[-1] += 1
else:
values.append(value)
count.append(1)
return count, values
def append(sizes, n_increment, size, type="uniform", radius_ref=None):
"""Append next increment size(s)."""
if type == "uniform":
sizes += [size] * n_increment
elif type == "logarithmic":
if not radius_ref:
if not len(sizes):
raise ValueError()
radius_ref = sizes[-1]
f = get_factor(n_increment, size, radius_ref)
sizes.append(f * radius_ref)
for _ in range(n_increment - 1):
sizes.append(f * sizes[-1])
def get_factor(n_increment, radius, radius_ref):
"""
Calculate f factor.
Note
----
Solve the equation DR * f + DR * f ** 2 + ... + DR * f ** n = RMAX.
This polynomial should have only one positive root.
"""
roots = np.roots(np.append(np.ones(n_increment), -radius / radius_ref))
roots = roots[::-1] # The real positive root seems to be the last one
# Still check that it's real and positive
f = None
for root in roots:
if np.isreal(root) and root > 0.0:
f = root.real
break
if f is None:
raise ValueError("no real positive root found.")
return f