Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions python/libneo/eqdsk_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ def write_array(fobj, arr):
fobj.write("\n")

with open(filename, 'w') as f:
f.write(eqdata['header'][:48])
f.write(f"{eqdata['header'][:48]:<48s}")

f.write(f" 0 {eqdata['nrgr']} {eqdata['nzgr']}\n")
f.write(f"{0:4d}{eqdata['nrgr']:4d}{eqdata['nzgr']:4d}\n")

write_field(f, eqdata['rboxlength'])
write_field(f, eqdata['zboxlength'])
Expand Down
71 changes: 71 additions & 0 deletions python/tests/test_eqdsk_base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Tests for the plain EQDSK reader/writer in libneo.eqdsk_base."""

import numpy as np
import pytest

from libneo.eqdsk_base import read_eqdsk, write_eqdsk


def _synthetic_eqdata(nrgr: int, nzgr: int) -> dict:
boundary = np.column_stack(
[2.0 + 0.5*np.cos(np.linspace(0.0, 2.0*np.pi, 33)),
0.5*np.sin(np.linspace(0.0, 2.0*np.pi, 33))]
)
return {
"header": "synthetic eqdsk for header format test ",
"nrgr": nrgr,
"nzgr": nzgr,
"rboxlength": 1.6,
"zboxlength": 1.6,
"R0": 2.0,
"rboxleft": 1.2,
"zboxmid": 0.0,
"Rpsi0": 2.0,
"Zpsi0": 0.0,
"PsiaxisVs": 0.0,
"PsiedgeVs": 0.15,
"Btor_at_R0": 2.0,
"Ip": 5.0e5,
"fprof": np.full(nrgr, 4.0),
"ptotprof": np.linspace(5.0e3, 0.0, nrgr),
"fdfdpsiprof": np.zeros(nrgr),
"dpressdpsiprof": np.full(nrgr, -3.0e4),
"PsiVs": np.linspace(0.0, 0.15, nrgr*nzgr).reshape(nzgr, nrgr),
"qprof": np.linspace(1.0, 4.0, nrgr),
"npbound": boundary.shape[0],
"nplimiter": boundary.shape[0],
"Lcfs": boundary,
"Limiter": 1.1*boundary,
}


@pytest.mark.parametrize("nrgr,nzgr", [(65, 65), (129, 129), (257, 129)])
def test_write_eqdsk_header_matches_3i4_columns(tmp_path, nrgr, nzgr):
"""The g-file header ends in (3i4) integer fields at columns 49-60.

Fortran readers (libneo read_eqfile1/read_eqfile2 and EFIT-compatible
codes) parse the grid dimensions with format (6a8,3i4), so the writer
must place idum, nw, nh in fixed four-character columns. Free-form
spacing breaks every grid dimension with three or more digits.
"""
path = tmp_path / "test.eqdsk"
write_eqdsk(path, _synthetic_eqdata(nrgr, nzgr))

header = path.read_text().splitlines()[0]
assert int(header[48:52]) == 0
assert int(header[52:56]) == nrgr
assert int(header[56:60]) == nzgr


@pytest.mark.parametrize("nrgr,nzgr", [(65, 65), (129, 129)])
def test_write_eqdsk_read_eqdsk_roundtrip(tmp_path, nrgr, nzgr):
path = tmp_path / "test.eqdsk"
eqdata = _synthetic_eqdata(nrgr, nzgr)
write_eqdsk(path, eqdata)
back = read_eqdsk(path)

assert back["nrgr"] == nrgr
assert back["nzgr"] == nzgr
np.testing.assert_allclose(back["PsiVs"], eqdata["PsiVs"],
atol=1e-6*eqdata["PsiedgeVs"])
np.testing.assert_allclose(back["qprof"], eqdata["qprof"], atol=1e-6)
Loading