Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
15 changes: 9 additions & 6 deletions mdadash/backend/analyses/com_distance.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ class COMDistance(WidgetBase):
"attribute": "periodic",
"name": "Periodic",
"description": "Select with periodic boundary conditions",
"type": "switch",
"type": "bool",
},
{
"attribute": "updating",
"name": "Updating",
"description": "Update selection during each timestep",
"type": "switch",
"type": "bool",
},
{
"attribute": "custom_title",
Expand All @@ -63,12 +63,12 @@ class COMDistance(WidgetBase):
"attribute": "max_distance",
"name": "Max distance",
"description": "Max distance for alert check",
"type": "int",
"type": "float",
},
{
"attribute": "max_distance_alert",
"name": "Alert if distance > 'Max distance'",
"type": "switch",
"type": "bool",
},
{
"attribute": "x_type",
Expand All @@ -83,7 +83,8 @@ class COMDistance(WidgetBase):

def __init__(self):
super().__init__()
self.maxlen = 100
self.default_maxlen = 100
self.maxlen = self.default_maxlen
self.steps = deque(maxlen=self.maxlen)
self.times = deque(maxlen=self.maxlen)
self.y_values = deque(maxlen=self.maxlen)
Expand All @@ -95,7 +96,7 @@ def __init__(self):
self.ag2 = None
self.title = "Distance between COMs"
self.custom_title = None
self.max_distance = 5
self.max_distance = 5.0
self.max_distance_alert = False
self.x_type = "step"
self.x_values = self.steps
Expand Down Expand Up @@ -130,6 +131,8 @@ def on_input_change(self, attribute, _old_value, new_value):
"""on_input_change handler"""
reset_plot = False
if attribute == "maxlen":
if new_value < 0:
self.maxlen = self.default_maxlen
reset_plot = True
elif attribute == "x_type":
self._set_x_values()
Expand Down
11 changes: 7 additions & 4 deletions mdadash/backend/analyses/energies.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ class EnergyWidgetBase:
def __init__(self):
super().__init__()
self.title = self.name
self.maxlen = 100
self.default_maxlen = 100
self.maxlen = self.default_maxlen
self.steps = deque(maxlen=self.maxlen)
self.times = deque(maxlen=self.maxlen)
self.y_values = deque(maxlen=self.maxlen)
Expand All @@ -63,9 +64,11 @@ def _set_x_values(self):
def on_input_change(self, attribute, _old_value, new_value):
"""on_input_change handler"""
if attribute == "maxlen":
self.steps = deque(maxlen=new_value)
self.times = deque(maxlen=new_value)
self.y_values = deque(maxlen=new_value)
if new_value < 0:
self.maxlen = self.default_maxlen
self.steps = deque(maxlen=self.maxlen)
self.times = deque(maxlen=self.maxlen)
self.y_values = deque(maxlen=self.maxlen)
self._set_x_values()
elif attribute == "x_type":
self._set_x_values()
Expand Down
21 changes: 17 additions & 4 deletions mdadash/backend/analyses/rog.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@ class ROG(WidgetBase):

name = "ROG"
description = "Radii of Gyration of a selection"
_analysis_mode = "per-frame"

_inputs = [
{
"attribute": "_analysis_mode",
"name": "Analysis mode",
"description": "The mode to run this analysis widget",
"type": "select",
"items": [
"per-frame",
],
},
{
"attribute": "selection",
"name": "Selection",
Expand All @@ -32,13 +42,13 @@ class ROG(WidgetBase):
"attribute": "periodic",
"name": "Periodic",
"description": "Select with periodic boundary conditions",
"type": "switch",
"type": "bool",
},
{
"attribute": "updating",
"name": "Updating",
"description": "Update selection during each timestep",
"type": "switch",
"type": "bool",
},
{
"attribute": "custom_title",
Expand All @@ -65,7 +75,8 @@ class ROG(WidgetBase):

def __init__(self):
super().__init__()
self.maxlen = 100
self.default_maxlen = 100
self.maxlen = self.default_maxlen
self.steps = deque(maxlen=self.maxlen)
self.times = deque(maxlen=self.maxlen)
self.y_values = deque(maxlen=self.maxlen)
Expand Down Expand Up @@ -99,10 +110,12 @@ def post_connect(self):
"""post_connect handler"""
self._update_selection()

def on_input_change(self, attribute, _old_value, _new_value):
def on_input_change(self, attribute, _old_value, new_value):
"""on_input_change handler"""
reset_plot = False
if attribute == "maxlen":
if new_value < 0:
self.maxlen = self.default_maxlen
reset_plot = True
elif attribute == "x_type":
self._set_x_values()
Expand Down
8 changes: 4 additions & 4 deletions mdadash/backend/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,7 @@ async def test_widget_runs(_client, imd_server):
assert uuid is not None
# test input changes
inputs = [
("maxlen", 10),
("maxlen", -1),
("x_type", "time"),
]
await _test_input_changes(uuid, inputs)
Expand All @@ -332,7 +332,7 @@ async def test_widget_runs(_client, imd_server):
maxlen = next(
(i for i in response["inputs"] if i.get("attribute") == "maxlen"), None
)
assert maxlen["value"] == 10
assert maxlen["value"] == 100

# connect to simulation
# widgets can be added even when the dashboard is not connected
Expand Down Expand Up @@ -379,7 +379,7 @@ async def test_widget_runs(_client, imd_server):
# test input changes
inputs = [
("selection", "protein"),
("maxlen", 10),
("maxlen", -1),
("x_type", "time"),
("updating", True),
]
Expand All @@ -395,7 +395,7 @@ async def test_widget_runs(_client, imd_server):
inputs = [
("selection1", "resid 1"),
("selection2", "resid 2"),
("maxlen", 10),
("maxlen", -1),
("x_type", "time"),
("updating", True),
]
Expand Down
4 changes: 3 additions & 1 deletion mdadash/backend/widgets/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,9 @@ def set_input(self, uuid: str, attribute: str, value: Any) -> bool:
"""
widget = self.instances[uuid]
old_value = getattr(widget, attribute, value)
setattr(widget, attribute, value)
old_type = type(old_value)
# set input using the same existing type
setattr(widget, attribute, old_type(value))
try:
widget.on_input_change(attribute, old_value, value)
widget._set_input_state(attribute)
Expand Down
10 changes: 10 additions & 0 deletions mdadash/frontend/src/__tests__/views/WidgetView.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ const widgetDetails = {
],
value: 'step',
},
{
attribute: '_analysis_mode',
name: 'Analysis mode',
description: 'The mode to run this analysis widget',
type: 'select',
items: ['per-frame', 'batch'],
},
],
}

Expand Down Expand Up @@ -193,6 +200,9 @@ describe('WidgetView.vue', () => {
attribute: 'x_type',
value: 'step',
})
// check select from dropdown
const mode = wrapper.findComponent('[data-attribute="_analysis_mode"]')
await mode.vm.$emit('update:modelValue', 'batch')
// check invalid input update
const maxlen = wrapper.find('[data-attribute="maxlen"]')
maxlen.find('input').setValue(100)
Expand Down
7 changes: 5 additions & 2 deletions mdadash/frontend/src/views/SettingsView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@
label="buffer_size"
variant="outlined"
v-model="settings.universe_configs[0].buffer_size"
control-variant="default"
control-variant="hidden"
hint="IMDFrameBuffer will be filled with as many IMDFrame fit in buffer_size bytes [10MB]"
persistent-hint
></v-number-input>
Expand All @@ -117,6 +117,9 @@
control-variant="default"
hint="Timeout for the socket in seconds [5]"
persistent-hint
:min="0"
:max="30"
:step="1"
></v-number-input>

<v-select
Expand Down Expand Up @@ -148,7 +151,7 @@
label="Total simulation steps"
variant="outlined"
v-model="settings.universe_configs[0].total_steps"
control-variant="default"
control-variant="hidden"
hint="Configuring this will enable showing % completion"
persistent-hint
></v-number-input>
Expand Down
22 changes: 7 additions & 15 deletions mdadash/frontend/src/views/WidgetView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@
@change="(e) => handleInputChange(input)"
@blur="input.error && handleInputChange(input)"
@click="input.type === 'toggle' && handleInputChange(input)"
@update:model-value="input.type === 'select' && handleInputChange(input)"
:rules="addRules(input.validations)"
:error-messages="input.error"
:items="input.items || []"
>
<template v-if="input.type === 'toggle'" #default>
<v-btn v-for="opt in input.options" :key="opt.value" :value="opt.value">
Expand Down Expand Up @@ -112,15 +114,7 @@ import { socket } from '@/socket'
import { useRoute } from 'vue-router'
import { ref, onMounted, onBeforeUnmount, inject } from 'vue'
import { mdiChevronDown, mdiChevronUp } from '@mdi/js'
import {
VTextField,
VSelect,
VCheckbox,
VNumberInput,
VSwitch,
VSlider,
VBtnToggle,
} from 'vuetify/components'
import { VTextField, VSelect, VNumberInput, VSwitch, VBtnToggle } from 'vuetify/components'

const route = useRoute()
const uuid = route.query.uuid
Expand All @@ -134,20 +128,18 @@ const isLoading = ref(false)
const componentMap = {
str: VTextField,
int: VNumberInput,
bool: VCheckbox,
switch: VSwitch,
float: VTextField,
bool: VSwitch,
select: VSelect,
slider: VSlider,
toggle: VBtnToggle,
}

const propsMap = {
str: {},
int: {},
bool: {},
switch: { density: 'compact', color: 'primary' },
float: { type: 'number', hideSpinButtons: true },
bool: { density: 'compact', color: 'primary' },
select: {},
slider: {},
toggle: { mandatory: 'true', color: 'primary', class: 'd-flex align-center', rounded: '1' },
}

Expand Down
Loading