Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding GUI #294

Merged
merged 29 commits into from
Jan 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7907864
added files for runing gui
shimwell Nov 19, 2022
a2ec280
basic layout for app start
shimwell Nov 19, 2022
6d958fd
added html viewer
shimwell Nov 19, 2022
35735aa
[skip ci] Apply formatting changes
shimwell Nov 19, 2022
26355d8
stp file download button added
shimwell Nov 19, 2022
0c0e6bf
merge conflict
shimwell Nov 19, 2022
5e8a763
[skip ci] Apply formatting changes
shimwell Nov 19, 2022
8db9595
progressed gui
shimwell Nov 20, 2022
2f4df8a
[skip ci] Apply formatting changes
shimwell Nov 20, 2022
3dd6f8a
tidy up comments
shimwell Nov 20, 2022
bec4031
merge conflict
shimwell Nov 20, 2022
d272173
[skip ci] Apply formatting changes
shimwell Nov 20, 2022
75aa7b7
corrected package name
shimwell Jan 8, 2023
11b4deb
added not implemented yet message
shimwell Jan 8, 2023
362a2d4
[skip ci] Apply formatting changes
shimwell Jan 8, 2023
3a4055f
bumped sphinx version
shimwell Jan 8, 2023
5bf18cb
Merge branch 'adding_streamlit_gui' of github.com:fusion-energy/param…
shimwell Jan 8, 2023
3c6afe0
added 2nd reactor
shimwell Jan 9, 2023
a21fcef
Merge branch 'develop' into adding_streamlit_gui
shimwell Jan 10, 2023
afd3943
[skip ci] shorter line
shimwell Jan 10, 2023
edcb049
added new dockerfile for gui
shimwell Jan 12, 2023
8517816
[skip ci] Apply formatting changes
shimwell Jan 12, 2023
1f0256f
gui working locally
shimwell Jan 12, 2023
036b52a
merge conflicts fixed
shimwell Jan 12, 2023
c403ce5
[skip ci] Apply formatting changes
shimwell Jan 12, 2023
05533a1
codiga suggestions
shimwell Jan 12, 2023
3387201
Merge branch 'adding_streamlit_gui' of github.com:fusion-energy/param…
shimwell Jan 12, 2023
fe5bc51
flake8 fix
shimwell Jan 12, 2023
6afc0e1
Merge pull request #288 from fusion-energy/adding_streamlit_gui
shimwell Jan 12, 2023
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
71 changes: 71 additions & 0 deletions .devcontainer/gui.Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# This Dockerfile creates a paramak Graphical User Interface that forms part
# of the xsplot.com webapps
#
# There are build args availalbe for specifying the:
# - cq_version
# The version of CadQuery to use master or 2.1
# Default is 2.1
# Options: [master, 2, 2.1]
#
# Example builds:
# Building using the defaults (cq_version master)
# docker build -t paramak_gui .
#
# Building to include cadquery master.
# Run command from within the base repository directory
# docker build -t paramak_gui --build-arg cq_version=master .
#
# Once build the dockerimage can be run in a few different ways.
#
# Run with the following command for a jupyter notebook interface
# docker run -p 8050:8050 paramak_gui


FROM continuumio/miniconda3:4.9.2 as dependencies
#
# By default this Dockerfile builds with the latest release of CadQuery 2
ARG cq_version=master

ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 \
DEBIAN_FRONTEND=noninteractive

RUN apt-get --allow-releaseinfo-change update
RUN apt-get update -y && \
apt-get upgrade -y

RUN apt-get install -y libgl1-mesa-glx libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev libosmesa6 libosmesa6-dev libgles2-mesa-dev curl imagemagick && \
apt-get clean

# Installing CadQuery and Gmsh
RUN echo installing CadQuery version $cq_version && \
conda install -c conda-forge -c python python=3.8 && \
conda install -c conda-forge -c cadquery cadquery="$cq_version" && \
conda install -c conda-forge moab && \
conda install -c conda-forge gmsh && \
conda install -c conda-forge python-gmsh && \
pip install jupyter-cadquery && \
conda clean -afy


FROM dependencies as install

ARG paramak_version=develop

RUN mkdir paramak
COPY src paramak/src/
COPY pyproject.toml paramak/pyproject.toml

COPY README.md paramak/README.md
COPY LICENSE.txt paramak/LICENSE.txt

RUN cd paramak && \
SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PARAMAK=${paramak_version} pip install .[gui]

ENV PORT 8501

EXPOSE 8501

# solves bug of streamlit not running in container
# https://github.com/streamlit/streamlit/issues/4842
ENTRYPOINT [ "streamlit", "run" ]
CMD [ "paramak/src/paramak/gui/app.py", "--server.headless", "true", "--server.fileWatcherType", "none", "--browser.gatherUsageStats", "false"]
7 changes: 7 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,16 @@ docs = [
"sphinx_autodoc_typehints",
"sphinxcadquery"
]
gui = [
"streamlit>=1.14.1",
"streamlit-image-select>=0.5.1",
]

[tool.black]
line-length = 120

[tool.setuptools]
package-dir = {"" = "src"}

[project.scripts]
paramak = "paramak.gui.launch:main"
229 changes: 229 additions & 0 deletions src/paramak/gui/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
import os
from pathlib import Path

import paramak
import streamlit as st
from streamlit_image_select import image_select

st.set_page_config(
page_title="Paramak",
page_icon="⚛",
layout="wide",
)

hide_streamlit_style = """
<style>
#MainMenu {visibility: hidden;}
footer {
visibility: hidden;
}
</style>
"""
st.markdown(hide_streamlit_style, unsafe_allow_html=True)
st.markdown("# Paramak GUI")
st.markdown(
"## A Graphical User Interface to [Paramak](https://github.com/fusion-energy/paramak) "
"for parametric fusion reactor geometry creation"
)

# FIXME get images names from https://paramak.readthedocs.io/en/main/API-Reference.html#parametric-reactors
reactor_image_links = [
"",
"https://user-images.githubusercontent.com/8583900/211223396-41ed8628-5352-4e7a-8c4a-97914174954e.png",
"https://user-images.githubusercontent.com/8583900/99136724-91af6f00-261e-11eb-9956-476b818a0ee3.png",
"https://user-images.githubusercontent.com/8583900/99136728-983de680-261e-11eb-8398-51ae433f5546.png",
"https://user-images.githubusercontent.com/8583900/99136727-94aa5f80-261e-11eb-965d-0ccceb2743fc.png",
"https://user-images.githubusercontent.com/8583900/99136719-8e1be800-261e-11eb-907d-a9bafaebdbb8.png",
"https://user-images.githubusercontent.com/8583900/99136731-9aa04080-261e-11eb-87a5-502708dfebcc.png",
"https://user-images.githubusercontent.com/8583900/99136734-9e33c780-261e-11eb-837b-16a0bc59f8a7.png",
"https://user-images.githubusercontent.com/8583900/110224418-4f62b400-7ed3-11eb-85f1-e40dc74f5671.png",
"https://user-images.githubusercontent.com/40028739/110248118-cf3e5c00-7f6f-11eb-9e68-864c1a1e8676.png",
"https://user-images.githubusercontent.com/8583900/100032191-5ae01280-2def-11eb-9654-47c3869b3a2c.png",
"https://user-images.githubusercontent.com/85617935/144303187-8cb71e2d-fc35-450f-a8f4-88b6650d56b7.png",
]

reactor_names = [
"0",
"FlfSystemCodeReactor",
"BallReactor",
"SingleNullBallReactor",
"SegmentedBlanketBallReactor",
"SubmersionTokamak",
"SingleNullSubmersionTokamak",
"CenterColumnStudyReactor",
"EuDemoFrom2015PaperDiagram",
"IterFrom2020PaperDiagram",
"SparcFrom2020PaperDiagram",
"NegativeTriangularityReactor",
]


selected_reactor_index = image_select(
label="Select a reactor",
images=reactor_image_links,
captions=reactor_names,
use_container_width=False,
return_value="index", # function returns index instead of image
index=0, # initial selected image is 0 which is blank
)

# gets the caption name of the selected image
selected_reactor = reactor_names[selected_reactor_index]

st.write(selected_reactor)
write_cad_buttons = True
col1, col2, col3 = st.columns([1, 1, 1])

if selected_reactor_index not in [0, None]:

if selected_reactor == "FlfSystemCodeReactor":
inner_blanket_radius = col1.number_input("inner blanket radius", value=100.0)
blanket_thickness = col1.number_input("blanket thickness", value=70.0)
blanket_height = col1.number_input("blanket height", value=500.0)
lower_blanket_thickness = col1.number_input("lower blanket thickness", value=50.0)
upper_blanket_thickness = col2.number_input("upper blanket thickness", value=40.0)
blanket_vv_gap = col2.number_input("blanket vv gap", value=20.0)
upper_vv_thickness = col2.number_input("upper vv thickness", value=10.0)
vv_thickness = col3.number_input("vv thickness", value=10.0)
lower_vv_thickness = col3.number_input("lower vv thickness", value=10.0)
rotation_angle = col3.number_input("rotation angle", value=180.0)

elif selected_reactor == "BallReactor":
inner_bore_radial_thickness = col1.number_input("inner_bore_radial_thickness", value=10.0)
inboard_tf_leg_radial_thickness = col1.number_input("inboard_tf_leg_radial_thickness", value=30.0)
center_column_shield_radial_thickness = col1.number_input("center_column_shield_radial_thickness", value=60.0)
divertor_radial_thickness = col1.number_input("divertor_radial_thickness", value=150.0)
inner_plasma_gap_radial_thickness = col1.number_input("inner_plasma_gap_radial_thickness", value=30.0)
plasma_radial_thickness = col1.number_input("plasma_radial_thickness", value=300.0)
outer_plasma_gap_radial_thickness = col1.number_input("outer_plasma_gap_radial_thickness", value=30.0)
firstwall_radial_thickness = col1.number_input("firstwall_radial_thickness", value=30.0)
blanket_radial_thickness = col2.number_input("firstwall_radial_thickness", value=50.0)
blanket_rear_wall_radial_thickness = col2.number_input("blanket_rear_wall_radial_thickness", value=30.0)
elongation = col2.number_input("elongation", value=2.0)
triangularity = col2.number_input("triangularity", value=0.55)
plasma_gap_vertical_thickness = col2.number_input("plasma_gap_vertical_thickness", value=50.0)
divertor_to_tf_gap_vertical_thickness = col2.number_input("divertor_to_tf_gap_vertical_thickness", value=0.0)
number_of_tf_coils = col2.number_input("number_of_tf_coils", value=12)
rear_blanket_to_tf_gap = col2.number_input("rear_blanket_to_tf_gap", value=0.0)
pf_coil_radial_thicknesses = col3.text_input(
"pf_coil_radial_thicknesses", value="50,40,50", key="input_pf_coil_radial_thicknesses"
)
pf_coil_vertical_thicknesses = col3.text_input("pf_coil_vertical_thicknesses", value="60,40,60", key="")
pf_coil_radial_position = col3.text_input(
"pf_coil_radial_position", value="500,550,500", key="input_pf_coil_radial_position"
)
pf_coil_vertical_position = col3.text_input(
"pf_coil_vertical_position", value="-250,0,250", key="input_pf_coil_vertical_position"
)
pf_coil_case_thicknesses = col3.text_input(
"pf_coil_case_thicknesses", value="5,5,5", key="input_pf_coil_case_thicknesses"
)
outboard_tf_coil_radial_thickness = col3.number_input(
"outboard_tf_coil_radial_thickness", value=50, key="input_outboard_tf_coil_radial_thickness"
)
outboard_tf_coil_poloidal_thickness = col3.number_input(
"outboard_tf_coil_radial_thickness", value=50, key="input_outboard_tf_coil_poloidal_thickness"
)
divertor_position = col3.selectbox("divertor_position", options=["both", "lower", "upper"])
rotation_angle = col3.number_input("rotation angle", value=180.0)
else:
write_cad_buttons = False
st.write(f"{selected_reactor} not implemented in GUI yet. Contributions are welcome")

if write_cad_buttons:
with st.spinner("Building the 3d model"):
if selected_reactor == "FlfSystemCodeReactor":
paramak_reactor = paramak.FlfSystemCodeReactor(
inner_blanket_radius=inner_blanket_radius,
blanket_thickness=blanket_thickness,
blanket_height=blanket_height,
lower_blanket_thickness=lower_blanket_thickness,
upper_blanket_thickness=upper_blanket_thickness,
blanket_vv_gap=blanket_vv_gap,
upper_vv_thickness=upper_vv_thickness,
vv_thickness=vv_thickness,
lower_vv_thickness=lower_vv_thickness,
rotation_angle=rotation_angle,
)
elif selected_reactor == "BallReactor":
paramak_reactor = paramak.BallReactor(
inner_bore_radial_thickness=inner_bore_radial_thickness,
inboard_tf_leg_radial_thickness=inboard_tf_leg_radial_thickness,
center_column_shield_radial_thickness=center_column_shield_radial_thickness,
divertor_radial_thickness=divertor_radial_thickness,
inner_plasma_gap_radial_thickness=inner_plasma_gap_radial_thickness,
plasma_radial_thickness=plasma_radial_thickness,
outer_plasma_gap_radial_thickness=outer_plasma_gap_radial_thickness,
firstwall_radial_thickness=firstwall_radial_thickness,
blanket_radial_thickness=blanket_radial_thickness,
blanket_rear_wall_radial_thickness=blanket_rear_wall_radial_thickness,
elongation=elongation,
triangularity=triangularity,
plasma_gap_vertical_thickness=plasma_gap_vertical_thickness,
divertor_to_tf_gap_vertical_thickness=divertor_to_tf_gap_vertical_thickness,
number_of_tf_coils=number_of_tf_coils,
rear_blanket_to_tf_gap=rear_blanket_to_tf_gap,
pf_coil_radial_thicknesses=[float(v) for v in pf_coil_radial_thicknesses.split(",")],
pf_coil_vertical_thicknesses=[float(v) for v in pf_coil_vertical_thicknesses.split(",")],
pf_coil_radial_position=[float(v) for v in pf_coil_radial_position.split(",")],
pf_coil_vertical_position=[float(v) for v in pf_coil_vertical_position.split(",")],
pf_coil_case_thicknesses=[float(v) for v in pf_coil_case_thicknesses.split(",")],
outboard_tf_coil_radial_thickness=outboard_tf_coil_radial_thickness,
outboard_tf_coil_poloidal_thickness=outboard_tf_coil_poloidal_thickness,
divertor_position=divertor_position,
rotation_angle=rotation_angle,
)

save_path = Path(os.path.realpath(__file__)).parent

save_html_file = save_path / "reactor.html"
paramak_reactor.export_html_3d(save_html_file)
with open(save_html_file, "r", encoding="UTF-8") as file1:
html_data = file1.read()

save_stp_file = save_path / "reactor.stp"
paramak_reactor.export_stp(str(save_stp_file))
with open(save_stp_file, "r", encoding="UTF-8") as file2:
stp_data = file2.read()

# save_stl_file = save_path / "reactor.stl"
# paramak_reactor.export_stl(str(save_stl_file))
# with open(save_stl_file, "r") as file3:
# stl_data = file3.read()

# FIXME fix so that it works
# save_h5m_file = save_path / "reactor.h5m"
# paramak_reactor.export_dagmc_h5m(str(save_h5m_file))
# with open(save_h5m_file, "r") as file4:
# h5m_data = file4.read()

col1_buttons, col2_buttons = st.columns([1, 1])

# FIXME see if on_click arg can be used to make stp file on demand
# https://docs.streamlit.io/library/api-reference/widgets/st.download_button
col1_buttons.download_button(
"Download CAD (STP format)",
stp_data,
file_name="paramak.stp",
)
col2_buttons.download_button(
"Download CAD (HTML format)",
html_data,
file_name="paramak.html",
)

# this is not currently working, perhaps due to binary files
# col2_buttons.download_button(
# "Download CAD (STL format)",
# stl_data,
# file_name="paramak.stl",
# )

# FIXME fix so that it works
# st.download_button(
# "Download DAGMC (h5m format)",
# stl_data,
# file_name="paramak.h5m",
# )

st.components.v1.html(html_data, height=800)
17 changes: 17 additions & 0 deletions src/paramak/gui/launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import runpy
import sys
from pathlib import Path

import paramak


def main():

path_to_app = str(Path(paramak.__path__[0]) / "gui" / "app.py")

sys.argv = ["streamlit", "run", path_to_app]
runpy.run_module("streamlit", run_name="__main__")


if __name__ == "__main__":
main()
9 changes: 4 additions & 5 deletions src/paramak/parametric_reactors/ball_reactor.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,12 @@ class BallReactor(paramak.Reactor):
divertor_to_tf_gap_vertical_thickness: the vertical thickness of the
gap between the divertor and the TF coils.
number_of_tf_coils: the number of tf coils
rear_blanket_to_tf_gap: the radial distance between the back of the
blankets and the start of the TF coils.
pf_coil_radial_thicknesses: the radial
thickness of each poloidal field coil.
pf_coil_vertical_thicknesses: the vertical
thickness of each poloidal field coil.
pf_coil_to_tf_coil_radial_gap: the radial distance
between the rear of the poloidal field coil and the toroidal field
coil.
pf_coil_radial_position: The radial (x) position(s) of the centers of
the poloidal field coils.
pf_coil_vertical_position: The vertical (z) position(s) of the centers
Expand All @@ -69,13 +68,13 @@ def __init__(
inner_plasma_gap_radial_thickness: float = 30.0,
plasma_radial_thickness: float = 300.0,
outer_plasma_gap_radial_thickness: float = 30.0,
plasma_gap_vertical_thickness: float = 50.0,
firstwall_radial_thickness: float = 30.0,
blanket_radial_thickness: float = 50.0,
blanket_rear_wall_radial_thickness: float = 30.0,
elongation: float = 2.0,
triangularity: float = 0.55,
divertor_to_tf_gap_vertical_thickness: Optional[float] = 0,
plasma_gap_vertical_thickness: float = 50.0,
divertor_to_tf_gap_vertical_thickness: Optional[float] = 0.0,
number_of_tf_coils: Optional[int] = 12,
rear_blanket_to_tf_gap: Optional[float] = None,
pf_coil_radial_thicknesses: List[float] = [],
Expand Down