Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

reset optimize state #4875

Merged
merged 5 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
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)"
YohannParis marked this conversation as resolved.
Show resolved Hide resolved
/>
<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
YohannParis marked this conversation as resolved.
Show resolved Hide resolved
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