Skip to content
Open
Show file tree
Hide file tree
Changes from 33 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
cb47065
added separatrix, contour center, and magnetic axes with clockable op…
prasad-sawantdesai Mar 26, 2026
7bc37fa
added quantities and spacing between plots
prasad-sawantdesai Mar 27, 2026
8759cdb
fixed integration with machine description
prasad-sawantdesai Mar 27, 2026
1b927c9
fixed colorbars position
prasad-sawantdesai Mar 27, 2026
7538154
fix color of separatrix
prasad-sawantdesai Mar 27, 2026
5d0d18d
remove legend for quantities
prasad-sawantdesai Mar 27, 2026
cd82599
fixed formatting
prasad-sawantdesai Mar 27, 2026
847b356
added documetation about tkinter installation
prasad-sawantdesai Mar 27, 2026
c5a3299
Add boundary overlays (outline, separatrix, x-points, strike-points, …
prasad-sawantdesai Mar 30, 2026
09ea0b8
do not join strike points and rename labels
prasad-sawantdesai Mar 30, 2026
0381773
changed the marker for current center
prasad-sawantdesai Mar 30, 2026
dfa98ea
reverted rho option and use of IMAS constants
prasad-sawantdesai Mar 31, 2026
e332fcb
fixed formatting issue
prasad-sawantdesai Mar 31, 2026
0ba5b0e
contour_tree implementation DD4
prasad-sawantdesai Mar 31, 2026
26bd780
removed boundary and made separatrix black
prasad-sawantdesai Mar 31, 2026
d570da9
Merge branch 'iterorganization:develop' into feature/add_separatrix_a…
prasad-sawantdesai May 4, 2026
e57c1ab
Merge branch 'iterorganization:develop' into feature/add_separatrix_a…
prasad-sawantdesai Jun 2, 2026
58b6352
added lazy=True and fixed bug in reading data
prasad-sawantdesai Jun 11, 2026
094c40f
magnetic_axis +, current center + , geometric axis x and separatrix …
prasad-sawantdesai Jun 11, 2026
0cd9c11
for DD3 read values from boundary x_point and strike_point
prasad-sawantdesai Jun 11, 2026
e46a8f2
plot rho2d with transpose
prasad-sawantdesai Jun 12, 2026
9c650a2
show URI on top left corner
prasad-sawantdesai Jun 12, 2026
863e09b
Do not show quantities at the start and make it visible/invisible bas…
prasad-sawantdesai Jun 12, 2026
d3246f9
add buttons to clear overlay show legends inside to save space and ba…
prasad-sawantdesai Jun 12, 2026
2be598a
added overlay CLI argument
prasad-sawantdesai Jun 12, 2026
1c13e23
fixed comment
prasad-sawantdesai Jun 12, 2026
692ead8
fixed provenance
prasad-sawantdesai Jun 12, 2026
10229bb
provenance if passed in center. do not show same uri if --md passed. …
prasad-sawantdesai Jun 15, 2026
612add8
removed unused import
prasad-sawantdesai Jun 15, 2026
afdc00b
read boundary/outline
prasad-sawantdesai Jun 15, 2026
d45066d
added plotting script provennace as title
prasad-sawantdesai Jun 15, 2026
d64ed81
Merge branch 'develop' into feature/add_separatrix_and_magnetic_axes_…
prasad-sawantdesai Jun 15, 2026
25d7bef
removed provenance flag and always showed title
prasad-sawantdesai Jun 15, 2026
a06d803
added --no-provenance
prasad-sawantdesai Jun 19, 2026
301de7f
fixed units, -p to --profiles,remove y axis labels
prasad-sawantdesai Jun 19, 2026
7745398
plot machine description with psi when using --no-overlay -md
prasad-sawantdesai Jun 19, 2026
aaec5d8
fix multiple URIs to single one if IDSes are coming from same data en…
prasad-sawantdesai Jun 19, 2026
2595404
show boundary/outline if present
prasad-sawantdesai Jun 22, 2026
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
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,20 @@ plotequilibrium --uri "imas:mdsplus?user=public;pulse=134174;run=117;database=IT

## Requirements

- Python ≥ 3.8
- IMAS Python Access Layer (`imas-python`)
- Python ≥ 3.10

### Installed automatically via pip
- NumPy, Matplotlib, Pandas
- Rich (for enhanced terminal output)

### Requires separate installation
- **Tkinter** — usually bundled with Python but may require system packages:
- Linux (Debian/Ubuntu): `sudo apt install python3-tk`
- Linux (RHEL/CentOS/Rocky): `sudo dnf install python3-tkinter`
- Windows: included in the [python.org](https://www.python.org/downloads/) installer ("tcl/tk and IDLE" component, enabled by default)
- macOS (python.org installer): included by default
- macOS (Homebrew): `brew install python-tk` (or `brew install python-tk@3.x` for a specific version)

## Documentation

Full documentation is available at the project repository. Each tool includes built-in help:
Expand Down
404 changes: 404 additions & 0 deletions idstools/compute/equilibrium.py

Large diffs are not rendered by default.

11 changes: 7 additions & 4 deletions idstools/domain/ecstray.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def __init__(self, equilibrium_ids: object, core_profiles_ids: object, waves_ids
# self.coreProfilesCompute = coreProfilesIds
self.waves_compute = WavesCompute(waves_ids)

def get_resonance_layer(self, coherent_wave_index, time_slice, n_harm=None):
def get_resonance_layer(self, coherent_wave_index, time_slice, n_harm=None, equilibrium_time_slice=None):
"""This function calculates and returns a dictionary (Resonance Layer) containing r and z values
corresponding to the resonance points based on the provided nHarm values, b_resonance, and b_total arrays.

Expand Down Expand Up @@ -56,11 +56,14 @@ def get_resonance_layer(self, coherent_wave_index, time_slice, n_harm=None):
"""
if n_harm is None:
n_harm = [1, 2, 3, 4]
if equilibrium_time_slice is None:
equilibrium_time_slice = time_slice

b_resonance = self.waves_compute.get_b_resonance(coherent_wave_index, time_slice, harmonic_frequencies=n_harm)
profile2d_index, b_total = self.equilibrium_compute.get_b_total(time_slice)
profile2d_index, b_total = self.equilibrium_compute.get_b_total(equilibrium_time_slice)
if profile2d_index != -99:
r = self.equilibrium_compute.ids.time_slice[time_slice].profiles_2d[profile2d_index].grid.dim1
z = self.equilibrium_compute.ids.time_slice[time_slice].profiles_2d[profile2d_index].grid.dim2
r = self.equilibrium_compute.ids.time_slice[equilibrium_time_slice].profiles_2d[profile2d_index].grid.dim1
z = self.equilibrium_compute.ids.time_slice[equilibrium_time_slice].profiles_2d[profile2d_index].grid.dim2

[nr, nz] = np.shape(b_total)
b_err = 10 / nr
Expand Down
5 changes: 1 addition & 4 deletions idstools/scripts/bin/plotcoresources
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ from idstools.utils.clihelper import (
dbentry_parser,
get_database_path,
get_file_name,
get_title,
rcparam_parser,
)
from idstools.utils.idslogger import setup_logger
Expand Down Expand Up @@ -98,11 +97,9 @@ if __name__ == "__main__":
ax_torque_waveform = canvas.add_axes(row=1, col=3)
ret = core_source_view.view_torque_waveform(ax_torque_waveform, time_slice)

canvas.set_text(text=f"{get_database_path(args, time_value=time_value)}")

canvas.fig.subplots_adjust(top=0.916, bottom=0.09, left=0.044, right=0.953, hspace=0.287, wspace=0.2)
canvas.get_current_fig_manager().set_window_title(os.path.basename(__file__))
canvas.fig.suptitle(get_title(args, "Core sources", time_value))
canvas.set_sup_title(get_database_path(args, time_value=time_value))
if args.save:
fname = get_file_name(args, os.path.basename(__file__) + "_core_sources", time_value)
if args.directory:
Expand Down
4 changes: 1 addition & 3 deletions idstools/scripts/bin/plotcoretransport
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ from idstools.utils.clihelper import (
dbentry_parser,
get_database_path,
get_file_name,
get_title,
rcparam_parser,
)
from idstools.utils.idslogger import setup_logger
Expand Down Expand Up @@ -175,8 +174,7 @@ if __name__ == "__main__":
model_index,
logscale=args.logscale,
)
canvas.set_text(text=f"{get_database_path(args, time_value=time_value)}")
canvas.fig.suptitle(get_title(args, "Core transport", time_value))
canvas.set_sup_title(get_database_path(args, time_value=time_value))
canvas.fig.subplots_adjust(top=0.9, bottom=0.094, left=0.035, right=0.948, hspace=0.417, wspace=0.117)
canvas.get_current_fig_manager().set_window_title(os.path.basename(__file__))
canvas.remove_empty_axes()
Expand Down
4 changes: 1 addition & 3 deletions idstools/scripts/bin/ploteccomposition
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ from idstools.utils.clihelper import (
dbentry_parser,
get_database_path,
get_file_name,
get_title,
rcparam_parser,
)
from idstools.utils.idslogger import setup_logger
Expand Down Expand Up @@ -113,8 +112,7 @@ if __name__ == "__main__":
waves_view.plot_ecrh_waveform(ax3, time_slice)
waves_view.plot_e_c_c_d_waveform(ax4, time_slice)

canvas.set_text(text=f"{get_database_path(args, time_value)}")
canvas.fig.suptitle(get_title(args, "EC Composition", time_value))
canvas.set_sup_title(get_database_path(args, time_value=time_value))
canvas.fig.subplots_adjust(top=0.941, bottom=0.122, left=0.052, right=0.925, hspace=0.2, wspace=0.2)
canvas.get_current_fig_manager().set_window_title(os.path.basename(__file__))

Expand Down
28 changes: 15 additions & 13 deletions idstools/scripts/bin/plotecray
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,8 @@ if __name__ == "__main__":
exit(1)

# Search for adequate time slice for display
time_array = ids_waves.time
ntime = len(ids_waves.time)
time_slice, time_value = get_nearest_time(time_array, args.time)
time_index_waves, time_value = get_nearest_time(ids_waves.time, args.time)
time_index_equilibrium, _ = get_nearest_time(ids_equilibrium.time, time_value)

if len(ids_waves.code.name) > 0:
logger.info(f"Code name = {ids_waves.code.name.upper()}")
Expand All @@ -159,13 +158,18 @@ if __name__ == "__main__":
wave_view = WavesView(ids_waves)
wave_compute = WavesCompute(ids_waves)

beam_tracing_dict = wave_compute.get_beam_tracing(time_slice)
beam_tracing_dict = wave_compute.get_beam_tracing(time_index_waves)
logger.info(
f"There are {beam_tracing_dict['active_beams_count']} active beam(s)"
f"and each beam has {beam_tracing_dict['max_total_beams']} ray(s)"
)

ecstra_view.plot_poloidal_view(ax_polview, coherent_wave_index=0, time_slice=time_slice)
ecstra_view.plot_poloidal_view(
ax_polview,
coherent_wave_index=0,
time_slice=time_index_waves,
equilibrium_time_slice=time_index_equilibrium,
)
if args.md is True:
args.md = ["wall", "pf_active"]

Expand Down Expand Up @@ -242,22 +246,20 @@ if __name__ == "__main__":

wave_view.plot_pol_view_traces(
ax_polview,
time_slice,
time_index_waves,
color=color,
style=style,
)

equi_view.plot_topplotequilibrium(ax_topview, time_slice)
wave_view.plot_top_view_traces(ax_topview, time_slice, color=color, style=style, label=label_code)

wave_view.plot_electron_power(ax_powview, time_slice, color=color, style=style)
wave_view.plot_power_flow_normal(ax_powparview, time_slice, color=color, style=style)
equi_view.plot_topplotequilibrium(ax_topview, time_index_equilibrium)
wave_view.plot_top_view_traces(ax_topview, time_index_waves, color=color, style=style, label=label_code)

canvas.set_text(text=f"{get_database_path(args, time_value=time_value)}")
wave_view.plot_electron_power(ax_powview, time_index_waves, color=color, style=style)
wave_view.plot_power_flow_normal(ax_powparview, time_index_waves, color=color, style=style)

canvas.fig.subplots_adjust(top=0.95, bottom=0.097, left=0, right=0.948, hspace=0.2, wspace=0.108)
canvas.get_current_fig_manager().set_window_title(os.path.basename(__file__))
canvas.fig.suptitle(get_title(args, "EC rays", time_value))
canvas.set_sup_title(get_database_path(args, time_value=time_value))

if args.save:
fname = get_file_name(args, os.path.basename(__file__) + "_EC_rays", time_value)
Expand Down
48 changes: 32 additions & 16 deletions idstools/scripts/bin/plotecstrayradiation
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import argparse
import logging
import os
import sys

from rich_argparse import RichHelpFormatter

Expand All @@ -19,7 +20,6 @@ from idstools.input_processing import (
from idstools.utils.clihelper import (
get_database_path,
get_file_name,
get_title,
rcparam_parser,
dbentry_parser,
)
Expand All @@ -32,6 +32,15 @@ from idstools.view.polygon import PolygonView
from idstools.view.waves import WavesView

logger = setup_logger("module", stdout_level=logging.INFO)


def _first_existing_path(*paths):
for path in paths:
if os.path.exists(path):
return path
return paths[-1]


if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="---- Shows electron cyclotron stray radiation information by showing different plots",
Expand Down Expand Up @@ -61,20 +70,28 @@ if __name__ == "__main__":
time_index_waves = 0

current_file_path = os.path.dirname(os.path.abspath(__file__))
source_tree_root = os.path.abspath(os.path.join(current_file_path, "../../.."))

scenario_file = os.path.join(current_file_path, "../resources/input/scenario.yaml")
wallfile = os.path.join(current_file_path, "../resources/input/wall2d.txt")
filelaunchers = os.path.join(current_file_path, "../resources/input/ec_waveforms.yaml")
path_result = os.path.join(current_file_path, "../resources/results/")

if not os.path.exists(scenario_file):
scenario_file = os.path.join(current_file_path, "input/scenario.yaml")
if not os.path.exists(wallfile):
wallfile = os.path.join(current_file_path, "input/wall2d.txt")
if not os.path.exists(filelaunchers):
filelaunchers = os.path.join(current_file_path, "input/ec_waveforms.yaml")
if not os.path.exists(path_result):
path_result = os.path.join(current_file_path, "results/")
scenario_file = _first_existing_path(
os.path.join(source_tree_root, "resources/input/scenario.yaml"),
os.path.join(sys.prefix, "bin/input/scenario.yaml"),
os.path.join(current_file_path, "input/scenario.yaml"),
)
wallfile = _first_existing_path(
os.path.join(source_tree_root, "resources/input/wall2d.txt"),
os.path.join(sys.prefix, "bin/input/wall2d.txt"),
os.path.join(current_file_path, "input/wall2d.txt"),
)
filelaunchers = _first_existing_path(
os.path.join(source_tree_root, "resources/input/ec_waveforms.yaml"),
os.path.join(sys.prefix, "bin/input/ec_waveforms.yaml"),
os.path.join(current_file_path, "input/ec_waveforms.yaml"),
)
path_result = _first_existing_path(
os.path.join(source_tree_root, "resources/results"),
os.path.join(sys.prefix, "bin/results"),
os.path.join(current_file_path, "results"),
)

wall2d = read_wall(wallfile)

Expand Down Expand Up @@ -166,7 +183,6 @@ if __name__ == "__main__":
ax_polygon, wall2d, beam_wall, coherent_wave_index, time_index_waves, time_index_waves
)

canvas.set_text(text=f"{get_database_path(args, time_value=time_value_equilibrium)}")
canvas.fig.subplots_adjust(
top=0.88,
bottom=0.11,
Expand All @@ -175,7 +191,7 @@ if __name__ == "__main__":
hspace=0.458,
wspace=0.234,
)
canvas.fig.suptitle(get_title(args, "EC Stray Radiation", time_value_equilibrium))
canvas.set_sup_title(get_database_path(args, time_value=time_value_equilibrium))
canvas.get_current_fig_manager().set_window_title(os.path.basename(__file__))
if args.save:
fname = get_file_name(args, f"{os.path.basename(__file__)}_Equilibrium", time_value_equilibrium)
Expand Down
5 changes: 1 addition & 4 deletions idstools/scripts/bin/plotedgeprofiles
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ from idstools.utils.clihelper import (
dbentry_parser,
get_database_path,
get_file_name,
get_title,
rcparam_parser,
)
from idstools.utils.idslogger import setup_logger
Expand Down Expand Up @@ -186,11 +185,9 @@ if __name__ == "__main__":

edge_profiles_view.view_equatorial_plane_and_diverter_density(ax4, time_slice, logscale=args.logscale)

canvas.set_text(text=f"{get_database_path(args, time_value=time_value)}")

canvas.fig.subplots_adjust(top=0.93, bottom=0.067, left=0.026, right=0.953, hspace=0.287, wspace=0.12)

canvas.fig.suptitle(get_title(args, "Edge Profiles", time_value))
canvas.set_sup_title(get_database_path(args, time_value=time_value))
canvas.get_current_fig_manager().set_window_title(os.path.basename(__file__))

if args.save:
Expand Down
Loading