Skip to content
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,17 @@ Changelog

Bug Fixes

- Fixes the possible permission error in `from_input_file` method of `Equilibrium`, `FourierRZToroidalSurface` and `FourierRZCurve` classes when used with a VMEC input file. Now the automatically generated DESC input file is written to a temporary file under `./tmp/`.

v0.17.1
-------

This patch release updates package dependencies to resolve critical incompatibilities between jax-related libraries. DESC versions 0.16.0 and 0.17.0 contain a known bug when used alongside jax-finufft v1.3.0, and we recommend that users upgrade to DESC version 0.17.1 to ensure environment stability.

If an immediate upgrade is not feasible, the issue can be mitigated by manually downgrading jax-finufft to version 1.2.0.

Bug Fixes

- Fixes incorrect units in the documentation of some curvature variables.
- Fixes SyntaxError thrown when loading hdf5 data from file-like objects.

Expand Down
5 changes: 4 additions & 1 deletion desc/input_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
import pathlib
import re
import tempfile
import warnings
from datetime import datetime

Expand Down Expand Up @@ -215,7 +216,9 @@
isVMEC = re.search(r"&INDATA", line, re.IGNORECASE)
if isVMEC:
print("Converting VMEC input to DESC input")
path = self.input_path + "_desc"
basename = os.path.basename(self.input_path) + "_desc"
tmpdir = tempfile.mkdtemp()

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When does the delete operation occur on tmpdir? Does it do so automatically when the function ends?
Another option is to use with, i.e.

with tempfile.TemporaryDirectory() as tmpdir:
    path = os.path.join(tmpdir, basename = os.path.basename(self.input_path) + "_desc")

though it could be essentially the same.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be cleared after the python process is terminated or the session on the cluster is closed or the system is rebooted on personal laptop, not immediately after the function call. These are the options listed on the web for "when the tmp is cleared?".

path = os.path.join(tmpdir, basename)

Check warning on line 221 in desc/input_reader.py

View check run for this annotation

Codecov / codecov/patch

desc/input_reader.py#L219-L221

Added lines #L219 - L221 were not covered by tests
InputReader.vmec_to_desc_input(self.input_path, path)
print("Generated DESC input file {}:".format(path))
return self.parse_inputs(path)
Expand Down
37 changes: 24 additions & 13 deletions tests/test_input_output.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ def test_vmec_input(tmpdir_factory):
with pytest.warns(UserWarning):
ir = InputReader(cl_args=[str(tmp_path)])
vmec_inputs = ir.inputs
# ir makes a VMEC file automatically
path_converted_file = tmpdir.join("input.DSHAPE_desc")
# also test making a DESC file from the ir.inputs manually
path = tmpdir.join("desc_from_vmec")
ir.write_desc_input(path, ir.inputs)
Expand All @@ -60,6 +58,12 @@ def test_vmec_input(tmpdir_factory):
correct_file_path = ".//tests//inputs//input.DSHAPE_desc"

# check DESC input file matches known correct one line-by-line
# above InputReader(cl_args=[str(tmp_path)]) generates a DESC input file
# inside unknown tmp folder, we re create the input file here at a specific
# location, so that we can compare
path_converted_file = tmpdir.join("input.DSHAPE_converted")
with pytest.warns(UserWarning):
InputReader.vmec_to_desc_input(input_path, str(path_converted_file))
with open(correct_file_path) as f:
lines_correct = f.readlines()
with open(path) as f:
Expand Down Expand Up @@ -238,20 +242,30 @@ def test_near_axis_input_files():
np.testing.assert_allclose(
inputs_desc[arg], inputs_vmec[arg], rtol=1e-6, atol=1e-8
)
if os.path.exists(".//tests//inputs//input.QSC_r2_5.5_vmec_desc"):
os.remove(".//tests//inputs//input.QSC_r2_5.5_vmec_desc")


@pytest.mark.unit
def test_from_input_file_equilibrium_desc_vmec_DSHAPE():
"""Test that from_input_file works for DESC input files."""
vmec_path = ".//tests//inputs//input.DSHAPE"
def test_from_input_file_equilibrium_desc_vmec_DSHAPE(tmp_path):
"""Test that from_input_file works for DESC and VMEC input files."""
desc_path = ".//tests//inputs//input.DSHAPE_desc"
kwargs = {"spectral_indexing": "fringe"}
with pytest.warns(UserWarning, match="Left handed"):
eq = Equilibrium.from_input_file(desc_path, **kwargs)
with pytest.warns(UserWarning):
eq_VMEC = Equilibrium.from_input_file(vmec_path, **kwargs)

# load VMEC input from a read-only directory to ensure temp file handling works
# Related to issue #2139
vmec_src = ".//tests//inputs//input.DSHAPE"
locked_dir = tmp_path / "locked"
locked_dir.mkdir()
shutil.copy(vmec_src, locked_dir / "input.DSHAPE")
os.chmod(locked_dir, 0o555)
try:
with pytest.warns(UserWarning):
eq_VMEC = Equilibrium.from_input_file(
str(locked_dir / "input.DSHAPE"), **kwargs
)
finally:
os.chmod(locked_dir, 0o755)

# make sure the loaded eqs are equivalent
np.testing.assert_allclose(eq.R_lmn, eq_VMEC.R_lmn)
Expand Down Expand Up @@ -304,9 +318,6 @@ def test_from_input_file_equilibrium_desc_vmec():
assert eq_VMEC.iota is None
assert eq.sym == eq_VMEC.sym

if os.path.exists(".//tests//inputs//input.QSC_r2_5.5_vmec_desc"):
os.remove(".//tests//inputs//input.QSC_r2_5.5_vmec_desc")


@pytest.mark.unit
def test_vmec_input_surface_threshold():
Expand Down Expand Up @@ -814,7 +825,7 @@ def test_io_OmnigenousField(tmpdir_factory):

@pytest.mark.unit
def test_io_file_like_object(tmpdir_factory):
"""Test loading an equilibrium from a file-like object (BytesIO)"""
"""Test loading an equilibrium from a file-like object (BytesIO)."""
file_path = "./tests/inputs/iotest_HELIOTRON.h5"
with open(file_path, "rb") as f:
file_like_obj = BytesIO(f.read())
Expand Down
Loading