Skip to content

Commit 2b618a5

Browse files
authored
Merge pull request #25 from dragos-ana/enable-exodus-support
feat: enable exodus support, add further function evaluations and fix evaluation mechanism
2 parents 0520390 + 3a6e5ad commit 2b618a5

File tree

10 files changed

+1076
-222
lines changed

10 files changed

+1076
-222
lines changed

src/fourc_webviewer/fourc_webserver.py

Lines changed: 95 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,22 +10,27 @@
1010
import numpy as np
1111
import pyvista as pv
1212
from fourcipp import CONFIG
13+
from fourcipp.fourc_input import FourCInput
1314
from trame.app import get_server
1415
from trame.decorators import TrameApp, change, controller
1516

1617
import fourc_webviewer.pyvista_render as pv_render
1718
from fourc_webviewer.gui_utils import create_gui
1819
from fourc_webviewer.input_file_utils.fourc_yaml_file_visualization import (
19-
convert_to_vtu,
2020
function_plot_figure,
21+
get_variable_names_in_funct_expression,
2122
)
2223
from fourc_webviewer.input_file_utils.io_utils import (
2324
create_file_object_for_browser,
2425
get_master_and_linked_material_indices,
26+
get_variable_data_by_name_in_funct_item,
2527
read_fourc_yaml_file,
2628
write_fourc_yaml_file,
2729
)
2830
from fourc_webviewer.python_utils import convert_string2number, find_value_recursively
31+
from fourc_webviewer.read_geometry_from_file import (
32+
FourCGeometry,
33+
)
2934

3035
# always set pyvista to plot off screen with Trame
3136
pv.OFF_SCREEN = True
@@ -102,10 +107,12 @@ def __init__(
102107
self.init_state_and_server_vars()
103108

104109
# convert file to vtu and create dedicated render objects
105-
self.state.vtu_path = convert_to_vtu(
106-
fourc_yaml_file,
107-
Path(self._server_vars["temp_dir_object"].name),
110+
fourc_geometry = FourCGeometry(
111+
fourc_yaml_file=fourc_yaml_file,
112+
temp_dir=Path(self._server_vars["temp_dir_object"].name),
108113
)
114+
self.state.vtu_path = fourc_geometry.vtu_file_path
115+
109116
if self.state.vtu_path == "":
110117
self.state.read_in_status = self.state.all_read_in_statuses[
111118
"vtu_conversion_error"
@@ -299,7 +306,14 @@ def init_general_sections_state_and_server_vars(self):
299306
self.state.json_schema = CONFIG.fourc_json_schema
300307

301308
# define substrings of section names to exclude
302-
substr_to_exclude = ["DESIGN", "TOPOLOGY", "ELEMENTS", "NODE", "FUNCT"]
309+
substr_to_exclude = [
310+
"DESIGN",
311+
"TOPOLOGY",
312+
"ELEMENTS",
313+
"NODE",
314+
"FUNCT",
315+
"GEOMETRY",
316+
]
303317
# define full section names to exclude
304318
sect_to_exclude = [
305319
"MATERIALS",
@@ -724,26 +738,81 @@ def init_funct_state_and_server_vars(self):
724738
# state variable (and the server variable)
725739
self.state.funct_section[funct_name] = {}
726740

727-
# go through component data and check whether the function
728-
# component is currently visualizable...
729-
for component_index, component_data in enumerate(funct_data):
730-
if not all(
731-
[
732-
(
733-
component_key
734-
in ["COMPONENT", "SYMBOLIC_FUNCTION_OF_SPACE_TIME"]
741+
# go through item data and check whether function
742+
# components are currently visualizable...
743+
for item_index, item_data in enumerate(funct_data):
744+
# check whether we have a component or a variable
745+
if "COMPONENT" in item_data:
746+
if not all(
747+
[
748+
(
749+
component_key
750+
in ["COMPONENT", "SYMBOLIC_FUNCTION_OF_SPACE_TIME"]
751+
)
752+
for component_key in item_data.keys()
753+
]
754+
):
755+
item_data["VISUALIZATION"] = False
756+
else:
757+
item_data["VISUALIZATION"] = True
758+
759+
# append the component to our state variable
760+
self.state.funct_section[funct_name][
761+
f"Component {item_data['COMPONENT']}"
762+
] = {k: v for k, v in item_data.items() if k != "PARSED_FUNCT"}
763+
764+
elif "VARIABLE" in item_data:
765+
supported_variable_types = ["linearinterpolation", "multifunction"]
766+
if not item_data["TYPE"]:
767+
raise Exception(
768+
f"Type has to be provided for variable with data {item_data}"
735769
)
736-
for component_key in component_data.keys()
737-
]
738-
):
739-
funct_items[funct_name][component_index]["VISUALIZATION"] = False
770+
item_data["VISUALIZATION"] = (
771+
item_data["TYPE"] in supported_variable_types
772+
)
773+
774+
# append the variable to our state variable
775+
self.state.funct_section[funct_name][
776+
f"Variable {item_data['VARIABLE']}: {item_data['NAME']}"
777+
] = {k: v for k, v in item_data.items()}
778+
740779
else:
741-
funct_items[funct_name][component_index]["VISUALIZATION"] = True
780+
# warning that this function item is not known
781+
print(f"Unknown function item {item_data} for funct {funct_name}!")
782+
783+
# we don't enable visualization
784+
item_data["VISUALIZATION"] = False
785+
786+
# append the variable to our state variable
787+
self.state.funct_section[funct_name][
788+
f"Function item {item_index}"
789+
] = {k: v for k, v in item_data.items()}
790+
791+
# knowing all variables of the function now, recheck whether the components are truly visualizable based on whether their contained variables are all visualizable / evaluable
792+
for item_index, item_data in enumerate(funct_data):
793+
# check whether we have a visualizable component
794+
if "COMPONENT" in item_data and item_data["VISUALIZATION"]:
795+
# get all variables contained within the functional expression of the component
796+
all_contained_var_names = get_variable_names_in_funct_expression(
797+
item_data["SYMBOLIC_FUNCTION_OF_SPACE_TIME"]
798+
)
742799

743-
# append the component to our state variable
744-
self.state.funct_section[funct_name][f"Item {component_index + 1}"] = {
745-
k: v for k, v in component_data.items() if k != "PARSED_FUNCT"
746-
}
800+
# loop through contained variables and see whether they are evaluable
801+
for contained_var_name in all_contained_var_names:
802+
# find the specific item within the function section for this variable
803+
var_data = get_variable_data_by_name_in_funct_item(
804+
funct_section_item=self.state.funct_section[funct_name],
805+
variable_name=contained_var_name,
806+
)
807+
if not var_data:
808+
raise Exception(
809+
f"Variable {contained_var_name} cannot be found in function item {item_data}!"
810+
)
811+
if not var_data["VISUALIZATION"]:
812+
self.state.funct_section[funct_name][
813+
f"Component {item_data['COMPONENT']}"
814+
]["VISUALIZATION"] = False
815+
break
747816

748817
# set user selection variables
749818
self.state.selected_funct = next(
@@ -1066,10 +1135,11 @@ def click_convert_button(self, **kwargs):
10661135
self.init_state_and_server_vars()
10671136

10681137
# convert to vtu
1069-
self.state.vtu_path = convert_to_vtu(
1070-
temp_fourc_yaml_file,
1071-
Path(self._server_vars["temp_dir_object"].name),
1138+
fourc_geometry = FourCGeometry(
1139+
fourc_yaml_file=temp_fourc_yaml_file,
1140+
temp_dir=Path(self._server_vars["temp_dir_object"].name),
10721141
)
1142+
self.state.vtu_path = fourc_geometry.vtu_file_path
10731143

10741144
# catch eventual conversion error
10751145
if self.state.vtu_path == "":

src/fourc_webviewer/gui_utils.py

Lines changed: 167 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -282,36 +282,166 @@ def _functions_panel(server):
282282
with html.Div(
283283
classes="d-flex align-center ga-3 mb-5 pl-5 w-full",
284284
):
285-
### --> see fourc_webserver specification on which function visualizations are currently supported
286-
html.Span("COMPONENT: ", classes="text-h6")
287-
html.Span(
288-
v_text=(
289-
"funct_section[selected_funct][selected_funct_item]['COMPONENT']",
290-
),
291-
)
292-
## show function string
285+
with html.Div(
286+
v_if=(
287+
"'COMPONENT' in funct_section[selected_funct][selected_funct_item]",
288+
)
289+
):
290+
### --> see fourc_webserver specification on which function visualizations are currently supported
291+
html.Span("COMPONENT: ", classes="text-h6")
292+
html.Span(
293+
v_text=(
294+
"funct_section[selected_funct][selected_funct_item]['COMPONENT']",
295+
),
296+
)
297+
## show function information
293298
with html.Div(
294299
classes="d-flex align-center ga-3 mb-5 pl-5 w-full",
295300
):
296-
### --> see fourc_webserver specification on which function visualizations are currently supported
297-
html.Span("FUNCTION: ", classes="text-h6")
298-
# view mode: text
299-
html.Span(
300-
v_if=("edit_mode == all_edit_modes['view_mode']",),
301-
v_text=(
302-
"funct_section[selected_funct][selected_funct_item]['SYMBOLIC_FUNCTION_OF_SPACE_TIME']",
303-
),
304-
)
305-
# edit mode: text field
306-
vuetify.VTextField(
307-
v_model=(
308-
"funct_section[selected_funct][selected_funct_item]['SYMBOLIC_FUNCTION_OF_SPACE_TIME']",
309-
),
310-
update_modelValue="flushState('funct_section')",
311-
v_if=("edit_mode == all_edit_modes['edit_mode']",),
312-
dense=True,
313-
hide_details=True,
314-
)
301+
# for function components: show the functional strings
302+
with html.Div(
303+
v_if=(
304+
"'COMPONENT' in funct_section[selected_funct][selected_funct_item]",
305+
)
306+
):
307+
### --> see fourc_webserver specification on which function visualizations are currently supported
308+
html.Span("FUNCTION: ", classes="text-h6")
309+
# view mode: text
310+
html.Span(
311+
v_if=("edit_mode == all_edit_modes['view_mode']",),
312+
v_text=(
313+
"funct_section[selected_funct][selected_funct_item]['SYMBOLIC_FUNCTION_OF_SPACE_TIME']",
314+
),
315+
)
316+
# edit mode: text field
317+
vuetify.VTextField(
318+
v_model=(
319+
"funct_section[selected_funct][selected_funct_item]['SYMBOLIC_FUNCTION_OF_SPACE_TIME']",
320+
),
321+
update_modelValue="flushState('funct_section')",
322+
v_if=("edit_mode == all_edit_modes['edit_mode']",),
323+
dense=True,
324+
hide_details=True,
325+
style="min-width: 200px; max-width: 400px;", # control width
326+
)
327+
# for variables: show type, times, and values
328+
with html.Div(
329+
v_if=(
330+
"'VARIABLE' in funct_section[selected_funct][selected_funct_item]",
331+
)
332+
):
333+
## -> type
334+
with html.Div():
335+
html.Span("TYPE: ", classes="text-h6")
336+
# view mode: text
337+
html.Span(
338+
v_if=("edit_mode == all_edit_modes['view_mode']",),
339+
v_text=(
340+
"funct_section[selected_funct][selected_funct_item]['TYPE']",
341+
),
342+
)
343+
# edit mode: text field
344+
vuetify.VTextField(
345+
v_model=(
346+
"funct_section[selected_funct][selected_funct_item]['TYPE']",
347+
),
348+
update_modelValue="flushState('funct_section')",
349+
v_if=("edit_mode == all_edit_modes['edit_mode']",),
350+
dense=True,
351+
hide_details=True,
352+
)
353+
354+
## -> times
355+
with html.Div():
356+
html.Span("TIMES: ", classes="text-h6")
357+
# view mode: text
358+
html.Span(
359+
v_if=("edit_mode == all_edit_modes['view_mode']",),
360+
v_text=(
361+
"funct_section[selected_funct][selected_funct_item]['TIMES']",
362+
),
363+
)
364+
# edit mode: list of text fields
365+
with html.Div(
366+
v_if=("edit_mode == all_edit_modes['edit_mode']",),
367+
):
368+
with html.Div(
369+
v_for="(time_instant, time_instant_index) in funct_section[selected_funct][selected_funct_item]['TIMES']",
370+
style="margin-bottom: 8px;", # spacing between fields
371+
):
372+
vuetify.VNumberInput(
373+
precision=("funct_plot['input_precision']",),
374+
v_model=(
375+
"funct_section[selected_funct][selected_funct_item]['TIMES'][time_instant_index]",
376+
),
377+
update_modelValue="flushState('funct_section')",
378+
dense=True,
379+
hide_details=True,
380+
style="min-width: 200px; max-width: 400px;", # control width
381+
)
382+
383+
## -> values / descriptions
384+
with html.Div(
385+
v_if=(
386+
"'VALUES' in funct_section[selected_funct][selected_funct_item]",
387+
)
388+
):
389+
html.Span("VALUES: ", classes="text-h6")
390+
# view mode: text
391+
html.Span(
392+
v_if=("edit_mode == all_edit_modes['view_mode']",),
393+
v_text=(
394+
"funct_section[selected_funct][selected_funct_item]['VALUES']",
395+
),
396+
)
397+
# edit mode: list of text fields
398+
with html.Div(
399+
v_if=("edit_mode == all_edit_modes['edit_mode']",),
400+
):
401+
with html.Div(
402+
v_for="(val, val_index) in funct_section[selected_funct][selected_funct_item]['VALUES']",
403+
style="margin-bottom: 8px;", # spacing between fields
404+
):
405+
vuetify.VNumberInput(
406+
precision=("funct_plot['input_precision']",),
407+
v_model=(
408+
"funct_section[selected_funct][selected_funct_item]['VALUES'][val_index]",
409+
),
410+
update_modelValue="flushState('funct_section')",
411+
dense=True,
412+
hide_details=True,
413+
style="min-width: 200px; max-width: 400px;", # control width
414+
)
415+
416+
with html.Div(
417+
v_if=(
418+
"'DESCRIPTION' in funct_section[selected_funct][selected_funct_item]",
419+
)
420+
):
421+
html.Span("DESCRIPTION: ", classes="text-h6")
422+
# view mode: text
423+
html.Span(
424+
v_if=("edit_mode == all_edit_modes['view_mode']",),
425+
v_text=(
426+
"funct_section[selected_funct][selected_funct_item]['DESCRIPTION']",
427+
),
428+
)
429+
# edit mode: list of text fields
430+
with html.Div(
431+
v_if=("edit_mode == all_edit_modes['edit_mode']",),
432+
):
433+
with html.Div(
434+
v_for="(val, val_index) in funct_section[selected_funct][selected_funct_item]['DESCRIPTION']",
435+
style="margin-bottom: 8px;", # spacing between fields
436+
):
437+
vuetify.VTextField(
438+
v_model="funct_section[selected_funct][selected_funct_item]['DESCRIPTION'][val_index]",
439+
update_modelValue="flushState('funct_section')",
440+
dense=True,
441+
hide_details=True,
442+
style="min-width: 200px; max-width: 400px;", # control width
443+
)
444+
315445
# next components: only in view mode
316446
with html.Div(
317447
v_if=("edit_mode == all_edit_modes['view_mode']",),
@@ -410,7 +540,16 @@ def _functions_panel(server):
410540
display_mode_bar="true",
411541
)
412542
server.controller.figure_update = figure.update
413-
server.controller.figure_update(function_plot_figure(server.state))
543+
if server.state.funct_section[
544+
server.state.selected_funct
545+
][
546+
server.state.selected_funct_item
547+
][
548+
"VISUALIZATION"
549+
]: # add this explicitly again here, to avoid prohibited server actions
550+
server.controller.figure_update(
551+
function_plot_figure(server.state)
552+
)
414553

415554
# here we define the GUI output of the non-visualizable function components
416555
with html.Div(

0 commit comments

Comments
 (0)