Skip to content

Commit

Permalink
reset optimize state (#4875)
Browse files Browse the repository at this point in the history
Co-authored-by: Cole Blanchard <[email protected]>
  • Loading branch information
blanchco and Cole Blanchard authored Sep 24, 2024
1 parent 5903e0a commit 2bd128b
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ref, computed } from 'vue';
import { DynamicIntervention } from '@/types/Types';
import { InterventionPolicyGroupForm } from '@/components/workflow/ops/optimize-ciemss/optimize-ciemss-operation';
import InputSwitch from 'primevue/inputswitch';
Expand All @@ -26,7 +26,7 @@ const props = defineProps<{

const emit = defineEmits(['update-self']);

const dynamicInterventions = ref<DynamicIntervention[]>(props.config.intervention.dynamicInterventions);
const dynamicInterventions = computed<DynamicIntervention[]>(() => props.config.intervention.dynamicInterventions);

const knobs = ref({
isActive: props.config.isActive ?? false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@
<div class="toolbar">
<p>Click Run to start optimization.</p>
<span class="flex gap-2">
<Button
label="Reset"
outlined
@click="resetState"
severity="secondary"
:disabled="_.isEmpty(node.outputs[0].value)"
/>
<tera-pyciemss-cancel-button class="mr-auto" :simulation-run-id="cancelRunId" />
<Button :disabled="isRunDisabled" label="Run" icon="pi pi-play" @click="runOptimize" />
</span>
Expand All @@ -25,7 +32,7 @@
<section class="form-section">
<h5>Success criteria <i v-tooltip="criteriaTooltip" class="pi pi-info-circle info-circle" /></h5>
<tera-optimize-criterion-group-form
v-for="(cfg, index) in node.state.constraintGroups"
v-for="(cfg, index) in knobs.constraintGroups"
:key="selectedOutputId + ':' + index"
:index="index"
:criterion="cfg"
Expand All @@ -45,19 +52,19 @@
Intervention policy
<i v-tooltip="interventionPolicyToolTip" class="pi pi-info-circle info-circle" />
</h5>
<template v-for="(cfg, idx) in node.state.interventionPolicyGroups">
<template v-for="(cfg, idx) in knobs.interventionPolicyGroups">
<tera-static-intervention-policy-group
v-if="cfg.intervention?.staticInterventions && cfg.intervention?.staticInterventions.length > 0"
:key="cfg.id || '' + idx"
:config="cfg"
@update-self="(config) => updateInterventionPolicyGroupForm(idx, config)"
/>
</template>
<section class="empty-state" v-if="node.state.interventionPolicyGroups.length === 0">
<section class="empty-state" v-if="knobs.interventionPolicyGroups.length === 0">
<!-- TODO: This only works if the user clicks refresh !?!? -->
<p class="mt-1">No intervention policies have been added.</p>
</section>
<template v-for="(cfg, idx) in node.state.interventionPolicyGroups">
<template v-for="(cfg, idx) in knobs.interventionPolicyGroups">
<tera-dynamic-intervention-policy-group
v-if="cfg.intervention?.dynamicInterventions && cfg.intervention?.dynamicInterventions.length > 0"
:key="idx"
Expand Down Expand Up @@ -305,7 +312,7 @@
<Accordion multiple :active-index="[0, 1, 2]">
<AccordionTab header="Success criteria">
<ul>
<li v-for="(_constraint, key) in node.state.constraintGroups" :key="key">
<li v-for="(_constraint, key) in knobs.constraintGroups" :key="key">
<vega-chart
expandable
are-embed-actions-visible
Expand Down Expand Up @@ -431,6 +438,7 @@ import MultiSelect from 'primevue/multiselect';
import { mergeResults, renameFnGenerator } from '@/components/workflow/ops/calibrate-ciemss/calibrate-utils';
import TeraInputNumber from '@/components/widgets/tera-input-number.vue';
import { CiemssPresetTypes, DrilldownTabs } from '@/types/common';
import { useConfirm } from 'primevue/useconfirm';
import teraOptimizeCriterionGroupForm from './tera-optimize-criterion-group-form.vue';
import TeraStaticInterventionPolicyGroup from './tera-static-intervention-policy-group.vue';
import TeraDynamicInterventionPolicyGroup from './tera-dynamic-intervention-policy-group.vue';
Expand All @@ -443,6 +451,8 @@ import {
OptimizationInterventionObjective
} from './optimize-ciemss-operation';
const confirm = useConfirm();
const isSidebarOpen = ref(true);
const props = defineProps<{
Expand All @@ -467,6 +477,8 @@ interface BasicKnobs {
optimizationRunId: string;
selectedInterventionVariables: string[];
selectedSimulationVariables: string[];
constraintGroups: Criterion[];
interventionPolicyGroups: InterventionPolicyGroupForm[];
}
const knobs = ref<BasicKnobs>({
Expand All @@ -479,7 +491,9 @@ const knobs = ref<BasicKnobs>({
postForecastRunId: props.node.state.postForecastRunId ?? '',
optimizationRunId: props.node.state.optimizationRunId ?? '',
selectedInterventionVariables: props.node.state.selectedInterventionVariables ?? [],
selectedSimulationVariables: props.node.state.selectedSimulationVariables ?? []
selectedSimulationVariables: props.node.state.selectedSimulationVariables ?? [],
constraintGroups: props.node.state.constraintGroups ?? [],
interventionPolicyGroups: props.node.state.interventionPolicyGroups ?? []
});
const criteriaTooltip = 'TODO';
Expand All @@ -502,9 +516,9 @@ const outputPanel = ref(null);
const chartSize = computed(() => drilldownChartSize(outputPanel.value));
const cancelRunId = computed(() => props.node.state.inProgressPostForecastId || props.node.state.inProgressOptimizeId);
const activePolicyGroups = computed(() => props.node.state.interventionPolicyGroups.filter((ele) => ele.isActive));
const activePolicyGroups = computed(() => knobs.value.interventionPolicyGroups.filter((ele) => ele.isActive));
const inactivePolicyGroups = computed(() => props.node.state.interventionPolicyGroups.filter((ele) => !ele.isActive));
const inactivePolicyGroups = computed(() => knobs.value.interventionPolicyGroups.filter((ele) => !ele.isActive));
let pyciemssMap: Record<string, string> = {};
const showSpinner = computed<boolean>(
Expand All @@ -515,11 +529,11 @@ const showModelModal = ref(false);
const displayOptimizationResultMessage = ref(true);
const isRunDisabled = computed(() => {
const activeConstraintGroups = props.node.state.constraintGroups.filter((ele) => ele.isActive);
const activeConstraintGroups = knobs.value.constraintGroups.filter((ele) => ele.isActive);
return (
activeConstraintGroups.length === 0 ||
!activeConstraintGroups.every((ele) => ele.targetVariable) ||
props.node.state.interventionPolicyGroups.length === 0 ||
knobs.value.interventionPolicyGroups.length === 0 ||
activePolicyGroups.value.length <= 0
);
});
Expand Down Expand Up @@ -583,35 +597,19 @@ const onSelection = (id: string) => {
};
const updateInterventionPolicyGroupForm = (index: number, config: InterventionPolicyGroupForm) => {
const state = _.cloneDeep(props.node.state);
if (!state.interventionPolicyGroups) return;
state.interventionPolicyGroups[index] = config;
emit('update-state', state);
knobs.value.interventionPolicyGroups[index] = config;
};
const addCriterionGroupForm = () => {
const state = _.cloneDeep(props.node.state);
if (!state.constraintGroups) return;
state.constraintGroups.push(defaultCriterion);
emit('update-state', state);
knobs.value.constraintGroups.push(defaultCriterion);
};
const deleteCriterionGroupForm = (index: number) => {
const state = _.cloneDeep(props.node.state);
if (!state.constraintGroups) return;
state.constraintGroups.splice(index, 1);
emit('update-state', state);
knobs.value.constraintGroups.splice(index, 1);
};
const updateCriterionGroupForm = (index: number, config: Criterion) => {
const state = _.cloneDeep(props.node.state);
if (!state.constraintGroups) return;
state.constraintGroups[index] = config;
emit('update-state', state);
knobs.value.constraintGroups[index] = config;
};
const toggleAdditionalOptions = () => {
Expand Down Expand Up @@ -695,11 +693,15 @@ const initialize = async () => {
const setInterventionPolicyGroups = (interventionPolicy: InterventionPolicy) => {
const state = _.cloneDeep(props.node.state);
// If already set + not changed since set, do not reset.
if (state.interventionPolicyGroups.length > 0 && state.interventionPolicyGroups[0].id === interventionPolicy.id) {
if (
knobs.value.interventionPolicyGroups.length > 0 &&
knobs.value.interventionPolicyGroups[0].id === interventionPolicy.id
) {
return;
}
state.interventionPolicyId = interventionPolicy.id ?? '';
state.interventionPolicyGroups = []; // Reset prior to populating.
knobs.value.interventionPolicyGroups = []; // Reset prior to populating.
if (interventionPolicy.interventions && interventionPolicy.interventions.length > 0) {
interventionPolicy.interventions.forEach((intervention) => {
const isNotActive = intervention.dynamicInterventions?.length > 0 || intervention.staticInterventions?.length > 1;
Expand All @@ -709,7 +711,7 @@ const setInterventionPolicyGroups = (interventionPolicy: InterventionPolicy) =>
newIntervention.isActive = !isNotActive;
newIntervention.startTimeGuess = intervention.staticInterventions[0]?.timestep;
newIntervention.initialGuessValue = intervention.staticInterventions[0]?.value;
state.interventionPolicyGroups.push(newIntervention);
knobs.value.interventionPolicyGroups.push(newIntervention);
});
}
emit('update-state', state);
Expand Down Expand Up @@ -755,7 +757,7 @@ const runOptimize = async () => {
});
// At the moment we only accept one intervention type. Pyciemss, pyciemss-service and this will all need to be updated.
// https://github.com/DARPA-ASKEM/terarium/issues/3909
const interventionType = props.node.state.interventionPolicyGroups[0].optimizationType;
const interventionType = knobs.value.interventionPolicyGroups[0].optimizationType;
// These are interventions to be optimized over.
const optimizeInterventions: OptimizeInterventions = {
Expand All @@ -771,7 +773,7 @@ const runOptimize = async () => {
const fixedInterventions: Intervention[] = _.cloneDeep(inactivePolicyGroups.value.map((ele) => ele.intervention));
const qois: OptimizeQoi[] = [];
const activeConstraintGroups = props.node.state.constraintGroups.filter((ele) => ele.isActive);
const activeConstraintGroups = knobs.value.constraintGroups.filter((ele) => ele.isActive);
activeConstraintGroups.forEach((constraintGroup) =>
qois.push({
contexts: [constraintGroup.targetVariable],
Expand Down Expand Up @@ -821,14 +823,14 @@ const setOutputSettingDefaults = () => {
const selectedSimulationVariables: Array<string> = [];
if (!knobs.value.selectedInterventionVariables.length) {
props.node.state.interventionPolicyGroups.forEach((intervention) =>
knobs.value.interventionPolicyGroups.forEach((intervention) =>
selectedInterventionVariables.push(intervention.intervention.appliedTo)
);
knobs.value.selectedInterventionVariables = [...new Set(selectedInterventionVariables)];
}
if (!knobs.value.selectedSimulationVariables.length) {
props.node.state.constraintGroups.forEach((constraint) => {
knobs.value.constraintGroups.forEach((constraint) => {
if (constraint.targetVariable) {
// Use modelStateAndObsOptions to map from value -> label as simulation selection uses S not S_State
const userSelection = modelStateAndObsOptions.value.find(
Expand Down Expand Up @@ -897,11 +899,9 @@ const setOutputValues = async () => {
};
const preProcessedInterventionsData = computed<Dictionary<Intervention[]>>(() => {
const state = _.cloneDeep(props.node.state);
// Combine before and after interventions
const combinedInterventions = [
...state.interventionPolicyGroups.flatMap((group) => group.intervention),
...knobs.value.interventionPolicyGroups.flatMap((group) => group.intervention),
...(optimizedInterventionPolicy.value?.interventions || [])
];
Expand All @@ -916,7 +916,7 @@ onMounted(async () => {
const preparedSuccessCriteriaCharts = computed(() => {
const postForecastRunId = props.node.state.postForecastRunId;
return props.node.state.constraintGroups
return knobs.value.constraintGroups
.filter((ele) => ele.isActive)
.map((constraint) =>
createSuccessCriteriaChart(
Expand Down Expand Up @@ -1031,6 +1031,21 @@ const onSaveForReuse = async () => {
}
};
// reset drilldown state
const resetState = () => {
confirm.require({
header: 'Reset to original optimized state',
message: 'Are you sure you want to reset the state?',
accept: () => {
// Retore to the original output port state
const outputPort = props.node.outputs.find((output) => output.id === selectedOutputId.value);
if (outputPort) {
knobs.value = cloneDeep(outputPort.state as OptimizeCiemssOperationState);
}
}
});
};
watch(
() => knobs.value,
async () => {
Expand All @@ -1045,6 +1060,8 @@ watch(
state.optimizationRunId = knobs.value.optimizationRunId;
state.selectedInterventionVariables = knobs.value.selectedInterventionVariables;
state.selectedSimulationVariables = knobs.value.selectedSimulationVariables;
state.constraintGroups = knobs.value.constraintGroups;
state.interventionPolicyGroups = knobs.value.interventionPolicyGroups;
emit('update-state', state);
},
{ deep: true }
Expand All @@ -1059,9 +1076,7 @@ watch(
initialize();
if (props.node.state.postForecastRunId !== '' && props.node.state.preForecastRunId !== '') {
// The run has finished
knobs.value.optimizationRunId = props.node.state.optimizationRunId;
knobs.value.postForecastRunId = props.node.state.postForecastRunId;
knobs.value.preForecastRunId = props.node.state.preForecastRunId;
knobs.value = cloneDeep(props.node.state);
setOutputValues();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@

<script setup lang="ts">
import _ from 'lodash';
import { ref } from 'vue';
import { ref, watch } from 'vue';
import Dropdown from 'primevue/dropdown';
import TeraInputText from '@/components/widgets/tera-input-text.vue';
import TeraInputNumber from '@/components/widgets/tera-input-number.vue';
Expand All @@ -90,6 +90,14 @@ const isEditing = ref<boolean>(false);
const onEdit = () => {
isEditing.value = !isEditing.value;
};
watch(
() => props.criterion,
() => {
config.value = _.cloneDeep(props.criterion);
},
{ immediate: true }
);
</script>

<style scoped>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
import Dropdown from 'primevue/dropdown';
import TeraInputNumber from '@/components/widgets/tera-input-number.vue';
import InputSwitch from 'primevue/inputswitch';
import { computed, ref } from 'vue';
import { computed, ref, watch } from 'vue';
import { StaticIntervention } from '@/types/Types';
import {
InterventionPolicyGroupForm,
Expand Down Expand Up @@ -151,6 +151,14 @@ const showNewValueOptions = computed(
knobs.value.optimizationType === OptimizationInterventionObjective.paramValue ||
knobs.value.optimizationType === OptimizationInterventionObjective.paramValueAndStartTime
);

watch(
() => props.config,
() => {
knobs.value = { ...props.config };
staticInterventions.value = knobs.value.intervention.staticInterventions;
}
);
</script>

<style scoped>
Expand Down

0 comments on commit 2bd128b

Please sign in to comment.