Skip to content

Commit 871db10

Browse files
committed
Add include files pop up
1 parent 98cad2d commit 871db10

File tree

2 files changed

+254
-45
lines changed

2 files changed

+254
-45
lines changed

src/fourc_webviewer/fourc_webserver.py

Lines changed: 196 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ def __init__(
6868

6969
self.server = get_server()
7070

71+
# initialize include upload value: False (bottom sheet with include upload is not displayed until there is a fourcyaml file uploaded)
72+
self.state.include_upload_open = False
73+
self.state.included_files = []
74+
7175
# declare server-side variable dict: variables which should not
7276
# be exposed to the client-side
7377
self._server_vars = {}
@@ -120,18 +124,11 @@ def __init__(
120124
# initialize state object
121125
self.init_state_and_server_vars()
122126

123-
# convert file to vtu and create dedicated render objects
124-
fourc_geometry = FourCGeometry(
125-
fourc_yaml_file=fourc_yaml_file,
126-
temp_dir=Path(self._server_vars["temp_dir_object"].name),
127-
)
128-
self.state.vtu_path = fourc_geometry.vtu_file_path
127+
if "render_window" not in self._actors:
128+
self._server_vars["render_window"] = pv.Plotter()
129+
self.state.vtu_path = ""
129130

130-
if self.state.vtu_path == "":
131-
self.state.read_in_status = self.state.all_read_in_statuses[
132-
"vtu_conversion_error"
133-
]
134-
self.init_pyvista_render_objects()
131+
self._server_vars["fourc_yaml_file_dir"] = Path(fourc_yaml_file).parent
135132

136133
# create ui
137134
create_gui(self.server, self._server_vars["render_window"])
@@ -267,11 +264,57 @@ def init_pyvista_render_objects(self):
267264
268265
The saved vtu file path is hereby utilized.
269266
"""
270-
if "render_window" not in self._actors:
271-
self._server_vars["render_window"] = pv.Plotter()
267+
# convert file to vtu and create dedicated render objects
268+
if not Path(
269+
self._server_vars["temp_dir_object"].name
270+
+ "\\"
271+
+ self._server_vars["fourc_yaml_name"]
272+
).exists():
273+
raise Exception(
274+
"File does not exist: "
275+
+ self._server_vars["temp_dir_object"].name
276+
+ "\\"
277+
+ self._server_vars["fourc_yaml_name"]
278+
)
279+
geometry_file_name = (
280+
self._server_vars["fourc_yaml_content"]
281+
.sections.get("STRUCTURE GEOMETRY", {})
282+
.get("FILE")
283+
)
284+
if geometry_file_name:
285+
if not Path(
286+
self._server_vars["temp_dir_object"].name
287+
+ "\\"
288+
+ Path(
289+
self._server_vars["fourc_yaml_content"]
290+
.sections.get("STRUCTURE GEOMETRY", {})
291+
.get("FILE")
292+
).name
293+
).exists():
294+
raise Exception(
295+
"File does not exist: "
296+
+ self._server_vars["temp_dir_object"].name
297+
+ "\\"
298+
+ Path(
299+
self._server_vars["fourc_yaml_content"]["STRUCTURE GEOMETRY"][
300+
"FILE"
301+
]
302+
).name
303+
)
304+
fourc_geometry = FourCGeometry(
305+
fourc_yaml_file=self._server_vars["temp_dir_object"].name
306+
+ "\\"
307+
+ self._server_vars["fourc_yaml_name"],
308+
temp_dir=Path(self._server_vars["temp_dir_object"].name),
309+
)
310+
self.state.vtu_path = fourc_geometry.vtu_file_path
272311

273-
self._server_vars["render_window"].clear_actors()
312+
if self.state.vtu_path == "":
313+
self.state.read_in_status = self.state.all_read_in_statuses[
314+
"vtu_conversion_error"
315+
]
274316

317+
self._server_vars["render_window"].clear_actors()
275318
problem_mesh = pv.read(self.state.vtu_path)
276319
# get problem mesh
277320
self._actors["problem_mesh"] = self._server_vars["render_window"].add_mesh(
@@ -334,6 +377,12 @@ def init_pyvista_render_objects(self):
334377
all_result_descriptions = self.state.result_description_section.keys()
335378

336379
for dc in all_result_descriptions:
380+
if (
381+
not self.state.result_description_section[dc]
382+
.get("PARAMETERS", {})
383+
.get("NODE")
384+
):
385+
continue
337386
node_coords = problem_mesh.points[
338387
self.state.result_description_section[dc]["PARAMETERS"]["NODE"] - 1,
339388
:,
@@ -351,6 +400,8 @@ def init_pyvista_render_objects(self):
351400
)
352401
self.update_pyvista_render_objects()
353402

403+
self._server_vars["render_window"].reset_camera()
404+
354405
def update_pyvista_render_objects(self):
355406
"""Update/ initialize pyvista view objects (reader, thresholds, global
356407
COS, ...) for the rendered window.
@@ -359,7 +410,7 @@ def update_pyvista_render_objects(self):
359410
"""
360411
legend_items = []
361412

362-
for dc in self._actors["result_description_nodes"].values():
413+
for dc in self._actors.get("result_description_nodes", {}).values():
363414
dc.SetVisibility(False)
364415
if (
365416
self.state.selected_main_section_name == "RESULT DESCRIPTION"
@@ -372,7 +423,7 @@ def update_pyvista_render_objects(self):
372423
].SetVisibility(True)
373424
legend_items.append(("Selected result description", "deepskyblue"))
374425

375-
for rd in self._actors["dc_geometry_entities"].values():
426+
for rd in self._actors.get("dc_geometry_entities", {}).values():
376427
rd.SetVisibility(False)
377428
if (
378429
self.state.selected_main_section_name == "DESIGN CONDITIONS"
@@ -384,7 +435,7 @@ def update_pyvista_render_objects(self):
384435
].SetVisibility(True)
385436
legend_items.append(("Selected design condition", "navy"))
386437

387-
for mat in self._actors["material_meshes"].values():
438+
for mat in self._actors.get("material_meshes", {}).values():
388439
mat.SetVisibility(False)
389440
if (
390441
self.state.selected_material
@@ -743,7 +794,9 @@ def init_result_description_state_and_server_vars(self):
743794

744795
# get result description section
745796
result_description_section = copy.deepcopy(
746-
self._server_vars["fourc_yaml_content"]["RESULT DESCRIPTION"]
797+
self._server_vars["fourc_yaml_content"].sections.get(
798+
"RESULT DESCRIPTION", {}
799+
)
747800
)
748801

749802
# initialize empty dict as the result description section
@@ -913,6 +966,10 @@ def init_funct_state_and_server_vars(self):
913966
all_contained_var_names = get_variable_names_in_funct_expression(
914967
item_data["SYMBOLIC_FUNCTION_OF_SPACE_TIME"]
915968
)
969+
if "e" in all_contained_var_names:
970+
all_contained_var_names.remove("e")
971+
if "E" in all_contained_var_names:
972+
all_contained_var_names.remove("E")
916973

917974
# loop through contained variables and see whether they are evaluable
918975
for contained_var_name in all_contained_var_names:
@@ -954,6 +1011,46 @@ def init_funct_state_and_server_vars(self):
9541011
6 # precision for the user input of the values defined above: x, y, z and t_max
9551012
)
9561013

1014+
def request_included_files(self):
1015+
"""Requests the included files from the user by opening a the include
1016+
files dialog and setting up the state variable accordingly."""
1017+
included_files = []
1018+
1019+
exo_file_name = Path(
1020+
self._server_vars.get("fourc_yaml_content")
1021+
.sections.get("STRUCTURE GEOMETRY", {})
1022+
.get("FILE")
1023+
or ""
1024+
).name
1025+
if exo_file_name:
1026+
exo_file_server = Path(
1027+
self._server_vars["fourc_yaml_file_dir"],
1028+
exo_file_name,
1029+
)
1030+
exo_temp_path = Path(
1031+
self._server_vars["temp_dir_object"].name,
1032+
exo_file_name,
1033+
)
1034+
if exo_file_server.is_file():
1035+
with open(exo_file_server, "rb") as fr:
1036+
with open(exo_temp_path, "wb") as fw:
1037+
fw.write(fr.read())
1038+
elif not exo_temp_path.is_file():
1039+
included_files.append(
1040+
{
1041+
"name": exo_file_name,
1042+
"uploaded": False,
1043+
"error": None,
1044+
"content": None,
1045+
}
1046+
)
1047+
1048+
self.state.included_files = included_files
1049+
if self.state.included_files:
1050+
self.state.include_upload_open = True
1051+
else:
1052+
self.confirm_included_files()
1053+
9571054
def sync_funct_section_from_state(self):
9581055
"""Syncs the server-side functions section based on the current values
9591056
of the dedicated state variables."""
@@ -1025,12 +1122,22 @@ def init_mode_state_vars(self):
10251122
def change_fourc_yaml_file(self, fourc_yaml_file, **kwargs):
10261123
"""Reaction to change of state.fourc_yaml_file."""
10271124

1125+
if not fourc_yaml_file or fourc_yaml_file["name"].split(".")[-1] not in [
1126+
"yaml",
1127+
"yml",
1128+
"DAT",
1129+
"dat",
1130+
]:
1131+
print(
1132+
"Warning: File does not have a .yml / .yaml / .dat / .DAT ending or is empty. Try opening another file."
1133+
)
1134+
return
10281135
# create temporary fourc yaml file from the content of the given file
10291136
temp_fourc_yaml_file = Path(
10301137
self._server_vars["temp_dir_object"].name, fourc_yaml_file["name"]
10311138
)
1032-
with open(temp_fourc_yaml_file, "w") as f:
1033-
f.writelines(fourc_yaml_file["content"].decode("utf-8"))
1139+
with open(temp_fourc_yaml_file, "wb") as f:
1140+
f.write(fourc_yaml_file["content"])
10341141

10351142
# read content, lines and other details of the given file
10361143
(
@@ -1042,12 +1149,63 @@ def change_fourc_yaml_file(self, fourc_yaml_file, **kwargs):
10421149
) = read_fourc_yaml_file(temp_fourc_yaml_file)
10431150
self._server_vars["fourc_yaml_name"] = Path(temp_fourc_yaml_file).name
10441151

1045-
# set vtu file path empty to make the convert button visible
1046-
# (only if the function was not run yet, i.e., after the
1047-
# initial rendering)
1048-
self._server_vars["render_count"]["change_fourc_yaml_file"] += 1
1049-
if self._server_vars["render_count"]["change_fourc_yaml_file"] > 1:
1050-
self.state.vtu_path = ""
1152+
if self._server_vars["fourc_yaml_read_in_status"]:
1153+
self.state.read_in_status = self.state.all_read_in_statuses["success"]
1154+
else:
1155+
self.state.read_in_status = self.state.all_read_in_statuses[
1156+
"validation_error"
1157+
]
1158+
1159+
self._server_vars["fourc_yaml_name"] = temp_fourc_yaml_file.name
1160+
1161+
self.request_included_files()
1162+
1163+
@controller.set("on_upload_include_file")
1164+
def on_upload_include_file(self, uploaded_file, index, **kwargs):
1165+
"""Gets called when an included file is uploaded.
1166+
1167+
Saves the uploaded file into the state variable.
1168+
"""
1169+
self.state.included_files[index]["content"] = uploaded_file
1170+
1171+
try:
1172+
if self.state.included_files[index]["name"] != uploaded_file["name"]:
1173+
self.state.included_files[index]["error"] = (
1174+
"File name mismatch. Expected: "
1175+
+ self.state.included_files[index]["name"]
1176+
)
1177+
elif self.state.included_files[index]["content"]["size"] == 0:
1178+
self.state.included_files[index]["error"] = "File is empty."
1179+
else:
1180+
self.state.included_files[index]["error"] = None
1181+
self.state.included_files[index]["uploaded"] = True
1182+
except Exception:
1183+
self.state.included_files[index]["error"] = "Please upload a file."
1184+
self.state.included_files[index]["uploaded"] = False
1185+
self.state.dirty("included_files")
1186+
self.state.flush()
1187+
1188+
@controller.set("confirm_included_files")
1189+
def confirm_included_files(self, **kwargs):
1190+
"""Gets called when the Accept button in the included files dialog is
1191+
pressed.
1192+
1193+
Saves all files into the temporary directory.
1194+
"""
1195+
self.state.include_upload_open = False
1196+
1197+
for included_file in self.state.included_files:
1198+
# create file in temp directory
1199+
included_file_path = Path(
1200+
self._server_vars["temp_dir_object"].name,
1201+
included_file["content"]["name"],
1202+
)
1203+
with open(included_file_path, "wb") as f:
1204+
f.write(included_file["content"]["content"])
1205+
1206+
self.init_state_and_server_vars()
1207+
1208+
self.init_pyvista_render_objects()
10511209

10521210
@change("export_fourc_yaml_path")
10531211
def change_export_fourc_yaml_path(self, export_fourc_yaml_path, **kwargs):
@@ -1082,7 +1240,6 @@ def change_selected_material(self, selected_material, **kwargs):
10821240
# material (if we are not in an initial rendering scenario)
10831241
if self._server_vars["render_count"]["change_selected_material"] > 0:
10841242
# first get the master material id
1085-
master_mat_id = self.determine_master_mat_ind_for_current_selection()
10861243

10871244
# update plotter / render objects
10881245
self.update_pyvista_render_objects()
@@ -1158,7 +1315,7 @@ def change_selected_funct(self, selected_funct, **kwargs):
11581315
# set the selected funct item to the first within the newly
11591316
# selected funct
11601317
self.state.selected_funct_item = next(
1161-
iter(self.state.funct_section[selected_funct])
1318+
iter(self.state.funct_section.get(selected_funct, {}))
11621319
)
11631320

11641321
# update plotly figure
@@ -1183,18 +1340,22 @@ def change_selected_funct_item(self, selected_funct_item, **kwargs):
11831340
def change_funct_plot(self, funct_plot, **kwargs):
11841341
"""Reaction to change of state.funct_plot."""
11851342
# update plotly figure
1186-
if self.state.funct_section[self.state.selected_funct][
1187-
self.state.selected_funct_item
1188-
]["VISUALIZATION"]:
1343+
if (
1344+
self.state.funct_section.get(self.state.selected_funct, {})
1345+
.get(self.state.selected_funct_item, {})
1346+
.get("VISUALIZATION")
1347+
):
11891348
self.server.controller.figure_update(function_plot_figure(self.state))
11901349

11911350
@change("funct_section")
11921351
def change_funct_section(self, funct_section, **kwargs):
11931352
"""Reaction to change of state.funct_section."""
11941353
# update plotly figure
1195-
if self.state.funct_section[self.state.selected_funct][
1196-
self.state.selected_funct_item
1197-
]["VISUALIZATION"]:
1354+
if (
1355+
self.state.funct_section.get(self.state.selected_funct, {})
1356+
.get(self.state.selected_funct_item, {})
1357+
.get("VISUALIZATION")
1358+
):
11981359
self.server.controller.figure_update(function_plot_figure(self.state))
11991360

12001361
#################################################
@@ -1281,12 +1442,7 @@ def click_convert_button(self, **kwargs):
12811442
# initialize state object
12821443
self.init_state_and_server_vars()
12831444

1284-
# convert to vtu
1285-
fourc_geometry = FourCGeometry(
1286-
fourc_yaml_file=temp_fourc_yaml_file,
1287-
temp_dir=Path(self._server_vars["temp_dir_object"].name),
1288-
)
1289-
self.state.vtu_path = fourc_geometry.vtu_file_path
1445+
self.init_pyvista_render_objects()
12901446

12911447
# catch eventual conversion error
12921448
if self.state.vtu_path == "":

0 commit comments

Comments
 (0)