Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
2 changes: 1 addition & 1 deletion docs/source/actor_visualization.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Available Settings

* Optional

- ***port***: (int) The port on which the visualization server will run. Defaults to `5006`.
- ***port***: (int) The port on which the visualization server will run. Defaults to `0`, indicating a random available port.
- ***throttle_interval***: (float) The minimum time in seconds between plot updates.
This can be used to prevent the visualization from slowing down if data arrives very quickly. Defaults to `0.1`.
- ***keep_alive***: (bool) If `True`, the visualization server will remain active after
Expand Down
Binary file added docs/source/images/automatic.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/ff_prime.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/source/images/ip_curve.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Manual
installing
usage
tips_and_tricks
training

.. toctree::
:caption: API docs
Expand Down
478 changes: 478 additions & 0 deletions docs/source/training.rst

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion imas_muscle3/actors/visualization_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ def main() -> None:
while instance.reuse_instance():
if first_run:
plot_file_path = instance.get_setting("plot_file_path", "str")
port = get_setting_optional(instance, "port", 5006)
# If port is not specified, use a random available port
port = get_setting_optional(instance, "port", 0)
# FIXME: there is an issue when the plotting takes much longer
# than it takes for data to arrive from the MUSCLE actor. As a
# remedy, set a plotting throttle interval.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"""
Example that plots the following:
- First wall and divertor from machine description IDS.
- Boundary outline from an equilibrium IDS
"""

import holoviews as hv
import numpy as np
import panel as pn
import xarray as xr

from imas_muscle3.visualization.base_plotter import BasePlotter
from imas_muscle3.visualization.base_state import BaseState


class State(BaseState):
def extract(self, ids):
if ids.metadata.name == "equilibrium":
self.extract_equilibrium(ids)

def extract_equilibrium(self, ids):
ts = ids.time_slice[0]
outline = ts.boundary.outline

boundary_data = xr.Dataset(
{
"r": (("time", "point"), [outline.r]),
"z": (("time", "point"), [outline.z]),
},
coords={
"time": [ids.time[0]],
"point": np.arange(len(outline.r)),
},
)

current_data = self.data.get("equilibrium")
if current_data is None:
self.data["equilibrium"] = boundary_data
else:
self.data["equilibrium"] = xr.concat(
[current_data, boundary_data], dim="time", join="outer"
)


class Plotter(BasePlotter):
DEFAULT_OPTS = hv.opts.Overlay(
xlim=(0, 13),
ylim=(-10, 10),
title="Wall and equilibrium boundary outline",
xlabel="r [m]",
ylabel="z [m]",
)

def get_dashboard(self):
elements = [
hv.DynamicMap(self._plot_boundary_outline),
hv.DynamicMap(self._plot_wall),
]
overlay = hv.Overlay(elements).collate().opts(self.DEFAULT_OPTS)
return pn.pane.HoloViews(overlay, width=800, height=1000)

@pn.depends("time")
def _plot_boundary_outline(self):
state = self.active_state.data.get("equilibrium")

if state is not None and "r" in state and "z" in state:
selected_data = state.sel(time=self.time)
r = selected_data.r.values
z = selected_data.z.values
else:
r, z = [], [], "Waiting for data..."

return hv.Curve((r, z)).opts(self.DEFAULT_OPTS)

def _plot_wall(self):
"""Generates path for limiter and divertor."""
paths = []
wall = self.active_state.md.get("wall")
if wall is not None:
for unit in wall.description_2d[0].limiter.unit:
name = str(unit.name)
r_vals = unit.outline.r
z_vals = unit.outline.z
paths.append((r_vals, z_vals, name))
return hv.Path(paths, vdims=["name"]).opts(
color="black",
line_width=2,
hover_tooltips=[("", "@name")],
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
ymmsl_version: v0.1
model:
name: test_model
components:
source_component:
implementation: source_component
ports:
o_i: [equilibrium_out]
source_component_md:
implementation: source_component
ports:
o_i: [wall_out, pf_active_out]
visualization_component:
implementation: visualization_component
ports:
s: [equilibrium_in, pf_active_md_in, wall_md_in]
conduits:
source_component.equilibrium_out: visualization_component.equilibrium_in
source_component_md.wall_out: visualization_component.wall_md_in
source_component_md.pf_active_out: visualization_component.pf_active_md_in
settings:
source_component.source_uri: imas:hdf5?path=/home/ITER/blokhus/public/imasdb/ITER/4/666666/3/
source_component_md.source_uri: imas:hdf5?path=/home/ITER/blokhus/public/imasdb/ITER/4/666666/3/
visualization_component.plot_file_path: /home/ITER/blokhus/projects/IMAS-MUSCLE3/imas_muscle3/visualization/examples/machine_description/machine_description.py
visualization_component.keep_alive: true
implementations:
visualization_component:
executable: python
args: -u -m imas_muscle3.actors.visualization_component
source_component:
executable: python
args: -u -m imas_muscle3.actors.source_component
resources:
source_component:
threads: 1
source_component_md:
threads: 1
visualization_component:
threads: 1
1 change: 0 additions & 1 deletion imas_muscle3/visualization/examples/pds/pds.ymmsl
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ settings:
source_component.source_uri: imas:hdf5?path=/home/sebbe/projects/iter_python/IMAS-MUSCLE3/data/pds_example
source_component_md.source_uri: imas:hdf5?path=/home/sebbe/projects/iter_python/Waveform-Editor/data/nice-input-dd4
visualization_component.plot_file_path: /home/sebbe/projects/iter_python/IMAS-MUSCLE3/imas_muscle3/visualization/examples/pds/pds.py
visualization_component.port: 5007
visualization_component.keep_alive: true
implementations:
visualization_component:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,8 @@ model:
conduits:
source_component.equilibrium_out: visualization_component.equilibrium_in
settings:
source_component.source_uri: imas:hdf5?path=/home/sebbe/projects/iter_python/IMAS-MUSCLE3/data/striped_eq
visualization_component.plot_file_path: /home/sebbe/projects/iter_python/IMAS-MUSCLE3/imas_muscle3/visualization/examples/simple_1d_plot/simple_1d_plot.py
visualization_component.port: 5007
source_component.source_uri: imas:hdf5?path=/home/ITER/blokhus/public/imasdb/ITER/4/666666/3/
visualization_component.plot_file_path: /home/ITER/blokhus/projects/IMAS-MUSCLE3/imas_muscle3/visualization/examples/simple_1d_plot/simple_1d_plot.py
visualization_component.throttle_interval: 0
visualization_component.keep_alive: true
implementations:
Expand Down
14 changes: 1 addition & 13 deletions imas_muscle3/visualization/visualization_actor.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import logging
import runpy
import webbrowser
from typing import Dict

import panel as pn
Expand Down Expand Up @@ -92,18 +91,7 @@ def _start_server(self) -> None:
self.server = pn.serve( # type: ignore[no-untyped-call]
self.dynamic_panel,
port=self.port,
show=False,
show=self.open_browser_on_start,
threaded=True,
start=True,
)
if self.open_browser_on_start:
self._open_browser()

def _open_browser(self) -> None:
"""Open the dashboard in the system web browser."""
url = f"http://localhost:{self.port}"
try:
webbrowser.open(url)
except Exception as e:
logger.warning(f"Could not open browser automatically: {e}")
logger.info(f"Dashboard is available at {url}")