Skip to content

Commit bc5e0eb

Browse files
authored
Merge pull request #440 from MetaCell/feature/389
#389 Set experiment parameters, fetch param on create, simulate, crea…
2 parents dff185b + 66be0dc commit bc5e0eb

File tree

3 files changed

+115
-26
lines changed

3 files changed

+115
-26
lines changed

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ipython-genutils==0.2.0
2020
ipywidgets==7.5.1
2121
jedi==0.17.0
2222
Jinja2==2.11.2
23+
jsonpickle==2.1.0
2324
jsonschema==3.2.0
2425
jupyter==1.0.0
2526
jupyter-client==6.1.3

webapp/components/experiments/ExperimentEdit.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import ParameterMenu from './ParameterMenu';
2626
import useStyles from './ExperimentEditStyle';
2727
import * as ExperimentHelper from './ExperimentHelper';
2828
import DialogBox from '../general/DialogBox';
29-
3029
const RANGE_VALUE = 0;
3130
const SUPPORTED_TYPES = [REAL_TYPE.INT, REAL_TYPE.FLOAT, REAL_TYPE.STR, REAL_TYPE.BOOL];
3231
const MAX_TRIALS = 100;
@@ -198,7 +197,7 @@ const ExperimentEdit = (props) => {
198197
const experiments = useSelector((state) => state.experiments.experiments);
199198

200199
let numberOfTrials = 1;
201-
200+
// const dispatch = useDispatch();
202201
const validateParameter = (param) => {
203202
let updatedParam = param;
204203
if (param.type === LIST) {

webapp/redux/middleware/middleware.js

Lines changed: 113 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable consistent-return */
12
import {
23
CLONE_EXPERIMENT,
34
GET_EXPERIMENTS,
@@ -7,6 +8,7 @@ import {
78
} from 'root/redux/actions/experiments';
89
import { NETPYNE_COMMANDS } from 'root/constants';
910
import * as GeppettoActions from '@metacell/geppetto-meta-client/common/actions';
11+
import * as ExperimentsApi from 'root/api/experiments';
1012
import {
1113
UPDATE_CARDS,
1214
CREATE_NETWORK,
@@ -27,6 +29,7 @@ import Utils from '../../Utils';
2729
import { downloadJsonResponse, downloadPythonResponse } from './utils';
2830
import * as Constants from '../../constants';
2931

32+
const SUPPORTED_TYPES = [Constants.REAL_TYPE.INT, Constants.REAL_TYPE.FLOAT, Constants.REAL_TYPE.STR, Constants.REAL_TYPE.BOOL];
3033
let previousLayout = {
3134
edit: undefined,
3235
network: undefined,
@@ -39,7 +42,7 @@ export const processError = (response) => {
3942
return {
4043
errorMessage: parsedResponse.message,
4144
errorDetails: parsedResponse.details,
42-
additionalInfo: parsedResponse.additionalInfo
45+
additionalInfo: parsedResponse.additionalInfo,
4346
};
4447
}
4548
return false;
@@ -109,18 +112,18 @@ const simulateNetwork = (payload) => createSimulateBackendCall(
109112

110113
class PythonMessageFilter {
111114
errorIds = new Set();
112-
shouldLaunch(e) {
113-
const errorId = e.additionalInfo?.sim_id ;
114-
if (!errorId)
115-
return true ;
116-
if (errorId)
117-
{
118-
if(this.errorIds.has(errorId))
119-
return false ;
120-
else {
121-
this.errorIds.add(errorId);
122-
return true ;
115+
116+
shouldLaunch (e) {
117+
const errorId = e.additionalInfo?.sim_id;
118+
if (!errorId) {
119+
return true;
120+
}
121+
if (errorId) {
122+
if (this.errorIds.has(errorId)) {
123+
return false;
123124
}
125+
this.errorIds.add(errorId);
126+
return true;
124127
}
125128
}
126129
}
@@ -150,10 +153,10 @@ export default (store) => (next) => (action) => {
150153

151154
const pythonErrorCallback = (error) => {
152155
console.debug(Utils.getPlainStackTrace(error.errorDetails));
153-
if (errorMessageFilter.shouldLaunch(error))
156+
if (errorMessageFilter.shouldLaunch(error)) {
154157
return next(openBackendErrorDialog(error));
155-
else
156-
return next(action);
158+
}
159+
return next(action);
157160
};
158161

159162
switch (action.type) {
@@ -185,21 +188,107 @@ export default (store) => (next) => (action) => {
185188
break;
186189
}
187190
case CREATE_NETWORK: {
188-
instantiateNetwork({})
189-
.then(toNetworkCallback(false), pythonErrorCallback);
191+
let allParams = true;
192+
ExperimentsApi.getParameters()
193+
.then((params) => {
194+
const flattened = Utils.flatten(params);
195+
const paramKeys = Object.keys(flattened);
196+
197+
const filteredKeys = paramKeys.filter((key) => {
198+
// TODO: avoid to fetch field twice!
199+
const field = Utils.getMetadataField(`netParams.${key}`);
200+
if (field && SUPPORTED_TYPES.includes(field.type)) {
201+
return true;
202+
}
203+
return false;
204+
});
205+
const expData = store.getState().experiments;
206+
expData?.inDesign?.params?.forEach((param) => {
207+
if (!filteredKeys.includes(param.mapsTo)) {
208+
pythonErrorCallback(
209+
{
210+
errorDetails: 'Missing Parameters',
211+
errorMessage: 'Error',
212+
},
213+
);
214+
allParams = false;
215+
}
216+
});
217+
if (allParams) {
218+
instantiateNetwork({})
219+
.then(toNetworkCallback(false), pythonErrorCallback);
220+
}
221+
}, pythonErrorCallback);
190222
break;
191223
}
192224
case CREATE_SIMULATE_NETWORK: {
193-
const payload = { allTrials: false, simId: new Date().getTime() }
194-
simulateNetwork(payload)
195-
.then(toNetworkCallback(false), pythonErrorCallback);
225+
let allParams = true;
226+
ExperimentsApi.getParameters()
227+
.then((params) => {
228+
const flattened = Utils.flatten(params);
229+
const paramKeys = Object.keys(flattened);
230+
231+
const filteredKeys = paramKeys.filter((key) => {
232+
// TODO: avoid to fetch field twice!
233+
const field = Utils.getMetadataField(`netParams.${key}`);
234+
if (field && SUPPORTED_TYPES.includes(field.type)) {
235+
return true;
236+
}
237+
return false;
238+
});
239+
const expData = store.getState().experiments;
240+
expData?.inDesign?.params?.forEach((param) => {
241+
if (!filteredKeys.includes(param.mapsTo)) {
242+
pythonErrorCallback(
243+
{
244+
errorDetails: 'Missing Parameters',
245+
errorMessage: 'Error',
246+
},
247+
);
248+
allParams = false;
249+
}
250+
});
251+
if (allParams) {
252+
simulateNetwork({ allTrials: false })
253+
.then(toNetworkCallback(false), pythonErrorCallback);
254+
}
255+
}, pythonErrorCallback);
196256
break;
197257
}
198-
case SIMULATE_NETWORK:
199-
const payload = { allTrials: action.payload, simId: new Date().getTime(), usePrevInst: false }
200-
simulateNetwork(payload)
201-
.then(toNetworkCallback(false), pythonErrorCallback);
258+
case SIMULATE_NETWORK: {
259+
let allParams = true;
260+
ExperimentsApi.getParameters()
261+
.then((params) => {
262+
const flattened = Utils.flatten(params);
263+
const paramKeys = Object.keys(flattened);
264+
265+
const filteredKeys = paramKeys.filter((key) => {
266+
// TODO: avoid to fetch field twice!
267+
const field = Utils.getMetadataField(`netParams.${key}`);
268+
if (field && SUPPORTED_TYPES.includes(field.type)) {
269+
return true;
270+
}
271+
return false;
272+
});
273+
const expData = store.getState().experiments;
274+
expData?.inDesign?.params?.forEach((param) => {
275+
if (!filteredKeys.includes(param.mapsTo)) {
276+
pythonErrorCallback(
277+
{
278+
errorDetails: 'Missing Parameters',
279+
errorMessage: 'Error',
280+
},
281+
);
282+
allParams = false;
283+
}
284+
});
285+
if (allParams) {
286+
simulateNetwork({ allTrials: action.payload, usePrevInst: false })
287+
.then(toNetworkCallback(false), pythonErrorCallback);
288+
}
289+
}, pythonErrorCallback);
202290
break;
291+
}
203292
case PYTHON_CALL: {
204293
const callback = (response) => {
205294
switch (action.cmd) {

0 commit comments

Comments
 (0)