Skip to content

Commit 1064577

Browse files
committed
Enable variable visualiz. in function definitions
- Enabled variable read-in and visualization in function definitions. As such, one now has components and variables (while components can contain variables). - Enabled linearinterpolation and multifunction variables by constructing functional expression strings from the respective times, values, and descriptions. - Also adapted the GUI to show the variables as well, in both view and edit mode. In the edit mode, solely the times and the values / the descriptions can be changed. We use number inputs where required to preserve the data types. - Added another default file containing an Exodus geometry (solid tutorial). The relevant tutorials for the upcoming 4C workshop are running now. - Attempted to rectify the ordering of nodes meshio -> lnmmeshio -> vtu. However, when switching up nodes in the current form, the boundary conditions will get shifted as well. Thus, we preserve it for now, even though the HEX27 elements are currently visualized wrongfully.
1 parent a272ec1 commit 1064577

File tree

8 files changed

+682
-90
lines changed

8 files changed

+682
-90
lines changed

src/fourc_webviewer/fourc_webserver.py

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
from fourc_webviewer.gui_utils import create_gui
1919
from fourc_webviewer.input_file_utils.fourc_yaml_file_visualization import (
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,
2526
read_fourc_yaml_file,
2627
write_fourc_yaml_file,
28+
get_variable_data_by_name_in_funct_item,
2729
)
2830
from fourc_webviewer.python_utils import convert_string2number, find_value_recursively
2931
from fourc_webviewer.read_geometry_from_file import (
@@ -737,26 +739,81 @@ def init_funct_state_and_server_vars(self):
737739
# state variable (and the server variable)
738740
self.state.funct_section[funct_name] = {}
739741

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

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

761818
# set user selection variables
762819
self.state.selected_funct = next(

src/fourc_webviewer/gui_utils.py

Lines changed: 165 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,14 @@ 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[server.state.selected_funct][
544+
server.state.selected_funct_item
545+
][
546+
"VISUALIZATION"
547+
]: # add this explicitly again here, to avoid prohibited server actions
548+
server.controller.figure_update(
549+
function_plot_figure(server.state)
550+
)
414551

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

0 commit comments

Comments
 (0)