From cdff73cda90ed180d2f02b6ec0e4b0df61e8bb73 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 1 Mar 2023 23:49:35 +0000 Subject: [PATCH 01/68] create schema conversion script --- react/utility/.gitignore | 2 + react/utility/README.md | 19 ++ react/utility/convertschema.js | 98 -------- react/utility/convertschema.ts | 424 +++++++++++++++++++++++++++++++++ 4 files changed, 445 insertions(+), 98 deletions(-) create mode 100644 react/utility/.gitignore create mode 100644 react/utility/README.md delete mode 100644 react/utility/convertschema.js create mode 100644 react/utility/convertschema.ts diff --git a/react/utility/.gitignore b/react/utility/.gitignore new file mode 100644 index 0000000000..3399890647 --- /dev/null +++ b/react/utility/.gitignore @@ -0,0 +1,2 @@ +*.json +convertschema.js diff --git a/react/utility/README.md b/react/utility/README.md new file mode 100644 index 0000000000..1805e6b91a --- /dev/null +++ b/react/utility/README.md @@ -0,0 +1,19 @@ +# Schema Conversion Script +## Setup +```npm install -g typescript commander``` +## Build +```tsc --target es6 --moduleResolution node convertschema.ts``` +## Run +```node convertschema.js [-o, --output ]``` +## Usage +After converting a schema file the `model` and `type` sections are ready to use. For views, two sections are handled, `view` and `unhandled`. +### Unhandled +This section contains all views that could not be converted with the script. They will need to be manually updated to the new format. +### View +Views are converted panel-wise from the old format. This section contains all of the panels in the new format. Additional steps are needed to complete the schema conversion. +* A `navTabs` layout needs to be created and the panels need to be separated between the tabs. +* Panels within each tab need to be placed inside a `waterfall` layout. +* Panels need a `title` attribute in their `config`. +* A `navbarModalButton` is needed to allow the simulation to be renamed. +* Report layouts need to be added to panels that would typically contain them. These are not defined in the schema in the old format. +* Hiding and showing logic for panels, fields, reports, etc, needs to be defined. diff --git a/react/utility/convertschema.js b/react/utility/convertschema.js deleted file mode 100644 index 88a3197b56..0000000000 --- a/react/utility/convertschema.js +++ /dev/null @@ -1,98 +0,0 @@ -let fs = require("fs") - -function convertModels(fileName) { - let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); - let fileJson = JSON.parse(fileString); - - let models = fileJson.model; - - let newModels = {}; - - for(let [modelName, model] of Object.entries(models)) { - let newModel = {}; - for(let [fieldName, field] of Object.entries(model)) { - let [name, typeString, defaultValue, description, min, max] = field; - newModel[fieldName] = { - displayName: name, - type: typeString, - defaultValue, - description, - min, - max - } - } - newModels[modelName] = newModel; - } - - fs.writeFileSync('new-' + fileName, JSON.stringify({ model: newModels })); -} - -function convertEnums(fileName) { - let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); - let fileJson = JSON.parse(fileString); - - let e = fileJson.enum; - let types = {}; - - for(let [enumName, allowedValues] of Object.entries(e)) { - types[enumName] = { - base: "Enum", - config: { - allowedValues - } - } - } - - fs.writeFileSync('new-' + fileName, JSON.stringify({ type: types })); -} - -function listTypes(fileName) { - let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); - let fileJson = JSON.parse(fileString); - let models = fileJson.model; - - let fieldTypes = new Set(); - for(let [modelName, model] of Object.entries(models)) { - for(let [fieldName, field] of Object.entries(model)) { - let [name, typeString, defaultValue, description, min, max] = field; - fieldTypes.add(typeString); - } - } - - fieldTypes.forEach(s => console.log(s)); -} - -function placeConfigInField(fileName) { - let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); - let fileJson = JSON.parse(fileString); - - let isObject = (v) => typeof(v) === 'object' && !Array.isArray(v) && v !== null; - let isArray = (v) => typeof(v) === 'object' && Array.isArray(v); - let recur = (obj) => { - if(isObject(obj)) { - obj = {...obj}; - if(obj.layout) { - // is a layout - let {layout, ...newObj} = obj; - return { - layout, - config: recur(newObj) - } - } else { - for(let fieldName of Object.keys(obj)) { - obj[fieldName] = recur(obj[fieldName]); - } - return obj; - } - } else if(isArray(obj)) { - return obj.map(v => recur(v)); - } else { - return obj; - } - } - fs.writeFileSync('new-' + fileName, JSON.stringify({ view: recur(fileJson.view) })); -} - -//placeConfigInField("jspec-schema.json"); -convertModels("warppba-schema.json"); -//convertEnums("warppba-schema.json"); diff --git a/react/utility/convertschema.ts b/react/utility/convertschema.ts new file mode 100644 index 0000000000..b3a464f018 --- /dev/null +++ b/react/utility/convertschema.ts @@ -0,0 +1,424 @@ +let fs = require("fs"); +let { Command } = require("commander"); + +class Dependency { + modelName: string; + fieldName: string; + + constructor(dependencyString: string) { + let { modelName, fieldName } = this.mapDependencyNameToParts(dependencyString); + this.modelName = modelName; + this.fieldName = fieldName; + } + + mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string } = (dep) => { + let [modelName, fieldName] = dep.split('.').filter((s: string) => s && s.length > 0); + return { + modelName, + fieldName + } + } + + getDependencyString: () => string = () => { + return this.modelName + "." + this.fieldName; + } +} + +function mapProperties(obj: {[key: string]: I}, mapFunc: (name: string, value: I) => O): {[key: string]: O} { + return Object.fromEntries( + Object.entries(obj).map(([propName, propValue]) => { + return [propName, mapFunc(propName, propValue)] + }) + ) +} + +type OldSchemaEnum = [ + value: string, + displayName: string +][] + +type SchemaLayoutJson = { + layout: string, + config: any +} + +type ScheamFieldJson = { + displayName: string, + type: string, + defaultValue?: T, + description?: string, + shown?: string, + min?: number, + max?: number +} + +type SchemaModelJson = { + [fieldName: string]: ScheamFieldJson +} + +type SchemaModelsJson = {[modelName: string]: SchemaModelJson}; + +type SchemaTypeJson = { + base: string, + config: {[key: string]: any} +} + +type SchemaRoutesJson = { + [key: string]: string +} + +type SchemaJson = { + constants: {[key: string]: any}, + type: {[typeName: string]: SchemaTypeJson}, + model: SchemaModelsJson, + view: SchemaLayoutJson[], + route: SchemaRoutesJson, + reactRoute: SchemaRoutesJson +} + +type OldSchemaModel = { + [fieldName: string]: [ + displayName: string, + typeName: string, + defaultValue: any, + description?: string, + min?: number, + max?: number + ] +} + +type OldSchemaModels = {[modelName: string]: OldSchemaModel}; +type OldSchemaView = {[key: string]: any}; +type OldSchemaViews = {[viewName: string]: OldSchemaView}; + +type OldSchema = { + enum: {[enumName: string]: OldSchemaEnum}, + model: OldSchemaModels + view: OldSchemaViews +} + + + +function readSchema(fileName: string): OldSchema { + let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); + let fileJson = JSON.parse(fileString) as OldSchema; + return fileJson; +} + +function mergeObjects(child: {[key: string]: any}, parents: {[key: string]: any}[]): {[key: string]: any} { + let no = {}; + (parents || []).forEach(o => Object.assign(no, o)); + Object.assign(no, child); + return no; +} + +function mergeArrays(child: any[], parents: any[][]): any[] { + let na = []; + (parents || []).forEach(a => na.push(...a)); + na.push(...child); + return na; +} + +function performInheritances(objects: {[key: string]: T}, mergeFunc: (original: T, inh: T[]) => T): {[key: string]: T} { + return Object.fromEntries( + Object.entries(objects).map(([key, value]) => { + if(key.startsWith("_")) { + return undefined; + } + let sup: string[] = value["_super"]; + if(sup) { + value["_super"] = undefined; + let inh: T[] = sup.filter(v => v !== "model" && v !== "view" && v !== "_").map(n => objects[n]); + return [ + key, + mergeFunc(value, inh) + ] + } + return [ + key, + value + ] + }).filter(e => e !== undefined) + ) +} + +function modelInheritances(models: OldSchemaModels): OldSchemaModels { + return performInheritances(models, (o, i) => mergeObjects(o, i)); +} + +function viewInheritances(views: OldSchemaViews): OldSchemaViews { + return performInheritances(views, (o, i) => { + let mergeField = (fieldName: string) => { + o[fieldName] = o[fieldName] || []; + o[fieldName] = mergeArrays(o[fieldName], i.map(v => v[fieldName] || {})) + if(Object.keys(o[fieldName]).length == 0) { + o[fieldName] = undefined; + } + } + mergeField("basic"); + mergeField("advanced"); + return o; + }) +} + +function convertSchema(schema: OldSchema) { + let oModels = modelInheritances(schema.model); + //saveSchema("omodels.json", oModels); + let models = mapProperties(oModels, (modelName, model) => convertModel(model)); + let types = mapProperties(schema.enum, (enumName, e) => convertEnum(e)); + + let views = []; + let uViews = []; + + let oViews = viewInheritances(schema.view); + //saveSchema("oviews.json", oViews) + mapProperties(oViews, (viewName, view) => { + let [converted, cv] = convertView(viewName, view, models); + if(converted) { + views.push(cv); + } else { + uViews.push(cv); + } + }) + + return { + model: models, + type: types, + view: views, + unhandled: uViews + } +} + +function convertModel(model: OldSchemaModel): SchemaModelJson { + let newModel = {}; + for(let [fieldName, field] of Object.entries(model)) { + let [name, typeString, defaultValue, description, min, max] = field; + newModel[fieldName] = { + displayName: name, + type: typeString, + defaultValue, + description, + min, + max + } + } + return newModel; +} + +function convertEnum(old: OldSchemaEnum): SchemaTypeJson { + return { + base: "Enum", + config: { + allowedValues: old + } + } +} + +function convertView(viewName: string, view: {[key: string]: any}, models: SchemaModelsJson): [converted: boolean, view: {[key: string]: any}] { + let keys = Object.keys(view); + + let withMeta = (viewName, view) => { + view["_NAME"] = viewName; + return view; + } + + if(keys.includes("basic") || keys.includes("advanced")) { + // is panel + return [true, withMeta(viewName, convertPanel(viewName, view, models))] + } else { + return [false, withMeta(viewName, view)]; + } +} + +function fullFieldName(fieldName: string, modelName: string) { + let r = /\./ + if(r.test(fieldName)) { + return fieldName; + } + return `${modelName}.${fieldName}`; +} + + +function convertPanel( + viewName: string, + view: {[key: string]: any}, + models: SchemaModelsJson +): {[key: string]: any} { + let modelName = viewName; + if(view.model) { + modelName = view.model; + } + + let convertPanelContents = (children: any[]): SchemaLayoutJson[] => { + let tabs: [name: string, views: any[]][] = []; + let convertArrayChild = (ac: any) => { + /** + * ac could be either + * [string, ...] as a tab or + * [[string, ...], ...] as a table + */ + if(Array.isArray(ac[0])) { + // is table + return fieldTableLayout(ac, modelName, models); + } else { + tabs.push([ac[0], convertPanelContents(ac[1])]) + return undefined; + } + } + + let newChildren = []; + let fieldNames = []; + let popFields = () => { + if(fieldNames.length > 0) { + newChildren.push(fieldListLayout(fieldNames)); + fieldNames = []; + } + } + for(let child of children) { + if(typeof child === "string") { + fieldNames.push(fullFieldName(child, modelName)); + } else { + popFields(); + if(Array.isArray(child)) { + let c = convertArrayChild(child); + if(c !== undefined) { + newChildren.push(c); + } + } else { + throw new Error(`unknown child=${JSON.stringify(child)}`); + } + } + } + popFields(); + + if(tabs.length > 0) { + newChildren.push(tabsLayout(tabs)) + } + + return newChildren; + } + + let config: {[key: string]: any} = {}; + + if(view.basic) { + config['basic'] = convertPanelContents(view.basic); + } + + if(view.advanced) { + config['advanced'] = convertPanelContents(view.advanced); + } + + return { + layout: "panel", + config + } +} + +function layout( + type: string, + config: {[key: string]: any} +) { + return { + layout: type, + config + } +} + +function tabsLayout( + tabs: [name: string, views: any[]][], + +): SchemaLayoutJson { + let tab = (name: string, views: any[]) => { + return { + name, + items: views + } + } + + return layout( + "tabs", + { + tabs: tabs.map(([name, views]) => tab(name, views)) + } + ) +} + +function fieldListLayout(fieldNames: string[]) { + return layout("fieldList", { + fields: fieldNames + }) +} + +function fieldTableLayout( + columns: [name: string, fieldNames: string[]][], + modelName: string, + models: SchemaModelsJson +) { + let columnNames = columns.map(([name,]) => name); + let rows: { + label: string, + description: string, + fields: string[] + }[] = []; + let lens = [...new Set(columns.map(([, fields]) => fields.length))]; + if(lens.length > 1) { + //throw new Error(`unequal table columns=${JSON.stringify(columns)} field lengths=${lens}`) + // return these broken into columns manually instead of as a table + return layout("hStack", { + items: columns.map(([name, fieldNames]) => { + return layout("vStack", { + items: [ + layout("text", { + type: "header", + align: "left", + text: name + }), + fieldListLayout(fieldNames) + ] + }) + }) + }) + } + if(lens.length > 0) { + let len = lens[0]; + for(let i = 0; i < len; i++) { + let fields = columns.map(([, fields]) => fullFieldName(fields[i], modelName)); + let dep = new Dependency(fields[0]); + let firstModelField = models[dep.modelName][dep.fieldName] + rows.push({ + label: firstModelField.displayName, + description: firstModelField.description, + fields + }) + } + } + return layout( + "fieldTable", + { + columns: columnNames, + rows + } + ) +} + +function saveSchema(fileName: string, schema): void { + fs.writeFileSync(fileName, JSON.stringify(schema)); +} + +let program = new Command(); +program +.arguments("") +.option("-o, --output ", "output filename") +.action((inFile: string, options: {output?: string}) => { + let defaultOutfile = () => { + let sep =inFile.indexOf("."); + if(sep < 0) { + return inFile + "-conv"; + } + + return inFile.substring(0, sep) + "-conv" + inFile.substring(sep); + } + let outFile = options.output || defaultOutfile(); + saveSchema(outFile, convertSchema(readSchema(inFile))); +}) +program.parse(); From 0fd5fd56060042f307b6cf70f1909f7a2247fff4 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 1 Mar 2023 23:52:04 +0000 Subject: [PATCH 02/68] remove old file --- react/utility/warppba-schema.json | 437 ------------------------------ 1 file changed, 437 deletions(-) delete mode 100644 react/utility/warppba-schema.json diff --git a/react/utility/warppba-schema.json b/react/utility/warppba-schema.json deleted file mode 100644 index e70bc3b04b..0000000000 --- a/react/utility/warppba-schema.json +++ /dev/null @@ -1,437 +0,0 @@ -{ - "enum": { - "BeamRadiusMethod": [ - ["a", "Absolute"], - ["s", "Scale to Electron Plasma"] - ], - "BeamBunchLengthMethod": [ - ["a", "Absolute"], - ["s", "Scale to Electron Plasma"] - ], - "Field": [ - ["E", "E - Electron field [V/m]"], - ["B", "B - Magnetic field [T]"], - ["J", "J - Particle current [A]"], - ["rho", "rho - Charge density [C/m³]"] - ], - "FieldCoordinate": [ - ["r", "r"], - ["z", "z"], - ["y", "y"], - ["x", "x"], - ["t", "t"] - ], - "FieldMode": [ - ["0", "0"], - ["1", "1"], - ["all", "all"] - ], - "FramesPerSecond": [ - ["1", "1"], - ["2", "2"], - ["5", "5"], - ["10", "10"], - ["15", "15"], - ["20", "20"] - ], - "GridDimensions": [ - ["a", "Absolute"], - ["s", "Scale to Laser Pulse"], - ["e", "Scale to Electron Plasma"] - ], - "PulseDimensions": [ - ["a", "Absolute"], - ["r", "Resonant with Plasma Density"] - ], - "Range1to8": [ - ["1", "1"], - ["2", "2"], - ["3", "3"], - ["4", "4"], - ["5", "5"], - ["6", "6"], - ["7", "7"], - ["8", "8"] - ], - "Range20to80": [ - ["20", "20"], - ["30", "30"], - ["40", "40"], - ["50", "50"], - ["60", "60"], - ["70", "70"], - ["80", "80"] - ], - "Range8to32": [ - ["8", "8"], - ["9", "9"], - ["10", "10"], - ["11", "11"], - ["12", "12"], - ["13", "13"], - ["14", "14"], - ["15", "15"], - ["16", "16"], - ["17", "17"], - ["18", "18"], - ["19", "19"], - ["20", "20"], - ["21", "21"], - ["22", "22"], - ["23", "23"], - ["24", "24"], - ["25", "25"], - ["26", "26"], - ["27", "27"], - ["28", "28"], - ["29", "29"], - ["30", "30"], - ["31", "31"], - ["32", "32"] - ], - "SourceType": [ - ["laserPulse", "Laser Pulse"], - ["electronBeam", "Electron Beam"] - ], - "XValue": [ - ["x", "x"], - ["y", "y"], - ["z", "z"], - ["ux", "ux"], - ["uy", "uy"], - ["uz", "uz"] - ], - "YValue": [ - ["x", "x"], - ["y", "y"], - ["z", "z"], - ["ux", "ux"], - ["uy", "uy"], - ["uz", "uz"] - ] - }, - "dynamicFiles": { - "sirepoLibs": { - "js": [ - "warppba.js" - ] - } - }, - "frameIdFields": { - "beamAnimation": [ - "x", - "y", - "histogramBins" - ], - "fieldAnimation": ["field", "coordinate", "mode"], - "particleAnimation": [ - "x", - "y", - "histogramBins", - "xMin", - "xMax", - "yMin", - "yMax", - "zMin", - "zMax", - "uxMin", - "uxMax", - "uyMin", - "uyMax", - "uzMin", - "uzMax" - ] - }, - "localRoutes": { - "source": { - "config": { - "controller": "WarpPBASourceController as source", - "templateUrl": "/static/html/warppba-source.html" - } - }, - "dynamics": { - "route": "/dynamics/:simulationId", - "config": { - "controller": "WarpPBADynamicsController as dynamics", - "templateUrl": "/static/html/warppba-dynamics.html" - } - } - }, - "model": { - "animation": { - "sbatchCores": ["Cores", "Integer", 4], - "jobRunMode": ["Execution Mode", "JobRunMode", "parallel"], - "tasksPerNode": ["Processes per node", "Integer", 32], - "sbatchHours": ["Hours", "Float", 0.4], - "sbatchQueue": ["Queue", "NERSCQueue", "debug"], - "sbatchProject": ["Project", "OptionalString", ""] - }, - "beamAnimation": { - "x": ["X Value", "XValue", "z"], - "y": ["Y Value", "YValue", "x"], - "histogramBins": ["Histogram Bins", "Integer", 100], - "framesPerSecond": ["Frames per Second", "FramesPerSecond", "20"], - "colorMap": ["Color Map", "ColorMap", "viridis"], - "notes": ["Notes", "Text", ""] - }, - "beamPreviewReport": { - "x": ["X Value", "XValue", "z"], - "y": ["Y Value", "YValue", "x"], - "histogramBins": ["Histogram Bins", "Integer", 100], - "notes": ["Notes", "Text", ""] - }, - "electronBeam": { - "charge": ["Charge [C]", "Float", 1e-8], - "energy": ["Energy [GeV]", "Float", 23], - "beamRadiusMethod": ["Beam Radius Method", "BeamRadiusMethod", "a"], - "transverseEmittance": ["Normalized Transverse Emittance", "Float", 0.00001], - "rmsRadius": ["RMS Radius [µm]", "Float", 15], - "beamBunchLengthMethod": ["Beam Bunch Length Method", "BeamBunchLengthMethod", "s"], - "rmsLength": ["RMS Length [µm]", "Float", 0], - "bunchLength": ["Bunch Length [µm]", "Float", 0] - }, - "electronPlasma": { - "density": ["Density [m⁻³]", "Float"], - "length": ["Length [mm]", "Float"], - "entranceRampLength": ["Entrance Ramp [mm]", "Float"], - "exitRampLength": ["Exit Ramp [mm]", "Float"] - }, - "laserPulse": { - "wavelength": ["Wavelength [µm]", "Float"], - "amplitude": ["Normalized Amplitude A₀", "Float"], - "polarizationAngle": ["Polarization Angle [rad]", "Float"], - "pulseDimensions": ["Pulse Dimensions", "PulseDimensions"], - "waist": ["Waist [µm]", "Float"], - "duration": ["Pulse Length [ps]", "Float"], - "length": ["Normalized Length", "Float"], - "spotSize": ["Normalized Transverse Spot Size", "Float"] - }, - "simulationGrid": { - "gridDimensions": ["Grid Dimensions", "GridDimensions"], - "rScale": ["R Domain Size", "Float", 4], - "rLength": ["R Length [µm]", "Float", 20.324980154380], - "rMin": ["R Min [µm]", "Float", 0], - "rMax": ["R Max [µm]", "Float", 20.324980154380], - "rCellsPerSpotSize": ["R Cells per Spot Size", "Range8to32", 8], - "rCount": ["R Number of Cells", "Integer", 32], - "rParticlesPerCell": ["R Particles per Cell", "Range1to8", "1"], - "zScale": ["Z Domain Size", "Float", 2], - "zLength": ["Z Length [µm]", "Float", 20.324980154631], - "zMin": ["Z Min [µm]", "Float", -20.324980154631], - "zMax": ["Z Max [µm]", "Float", 1.60], - "zCellsPerWavelength": ["Z Cells per Laser Wavelength", "Range8to32", "8"], - "zCount": ["Z Number of Cells", "Integer", 214], - "zParticlesPerCell": ["Z Particles per Cell", "Range1to8", "2"], - "rCellResolution": ["R Cells per Plasma Wavelength", "Range20to80", "40"], - "zCellResolution": ["Z Cell per Plasma Wavelength", "Range20to80", "40"] - }, - "simulation": { - "sourceType": ["Source Type", "SourceType", "laserPulse"] - }, - "particleAnimation": { - "x": ["X Value", "XValue", "z"], - "y": ["Y Value", "YValue", "x"], - "histogramBins": ["Histogram Bins", "Integer", 100], - "framesPerSecond": ["Frames per Second", "FramesPerSecond", "20"], - "xMin": ["Minimum X [µm]", "Float", 0], - "xMax": ["Maximum X [µm]", "Float", 0], - "yMin": ["Minimum Y [µm]", "Float", 0], - "yMax": ["Maximum Y [µm]", "Float", 0], - "zMin": ["Minimum Z [µm]", "Float", 0], - "zMax": ["Maximum Z [µm]", "Float", 0], - "uxMin": ["Minimum UX [mc]", "Float", 0], - "uxMax": ["Maximum UX [mc]", "Float", 0], - "uyMin": ["Minimum UY [mc]", "Float", 0], - "uyMax": ["Maximum UY [mc]", "Float", 0], - "uzMin": ["Minimum UZ [mc]", "Float", 0], - "uzMax": ["Maximum UZ [mc]", "Float", 0], - "colorMap": ["Color Map", "ColorMap", "viridis"], - "notes": ["Notes", "Text", ""] - }, - "fieldAnimation": { - "field": ["Field", "Field"], - "coordinate": ["Coordinate", "FieldCoordinate"], - "mode": ["Mode", "FieldMode"], - "framesPerSecond": ["Frames per Second", "FramesPerSecond"], - "colorMap": ["Color Map", "ColorMap", "viridis"], - "notes": ["Notes", "Text", ""] - }, - "laserPreviewReport": { - "field": ["Field", "Field", "E"], - "coordinate": ["Coordinate", "FieldCoordinate", "y"], - "mode": ["Mode", "FieldMode", "1"], - "colorMap": ["Color Map", "ColorMap", "viridis"], - "notes": ["Notes", "Text", ""] - }, - "simulationStatus": {} - }, - "strings": { - "initMessage": "Initializing Laser Pulse and Plasma" - }, - "view": { - "beamAnimation": { - "title": "Electron Beam Animation", - "advanced": [ - "x", - "y", - "histogramBins", - "framesPerSecond", - "colorMap", - "notes" - ] - }, - "beamPreviewReport": { - "title": "Electron Beam Preview Report", - "advanced": [ - "x", - "y", - "histogramBins", - "notes" - ] - }, - "electronBeam": { - "title": "Electron Beam", - "basic": [ - "charge", - "energy" - ], - "advanced": [ - "charge", - "energy", - "beamRadiusMethod", - "transverseEmittance", - "rmsRadius", - "beamBunchLengthMethod", - "rmsLength", - "bunchLength" - ] - }, - "electronPlasma": { - "title": "Electron Plasma", - "basic": [ - "density", - "length" - ], - "advanced": [ - "density", - "length", - "entranceRampLength", - "exitRampLength" - ] - }, - "simulationGrid": { - "title": "Simulation Grid", - "basic": [ - "gridDimensions" - ], - "advanced": [ - "gridDimensions", - [ - ["R", [ - "rScale", - "rLength", - "rMin", - "rMax", - "rCellsPerSpotSize", - "rCellResolution", - "rCount", - "rParticlesPerCell" - ]], - ["Z", [ - "zScale", - "zLength", - "zMin", - "zMax", - "zCellsPerWavelength", - "zCellResolution", - "zCount", - "zParticlesPerCell" - ]] - ] - ] - }, - "laserPulse": { - "title": "Laser Pulse", - "basic": [ - "wavelength", - "amplitude", - "pulseDimensions", - "length", - "spotSize", - "waist", - "duration" - ], - "advanced": [ - "wavelength", - "amplitude", - "polarizationAngle", - "pulseDimensions", - "length", - "spotSize", - "waist", - "duration" - ] - }, - "simulation": { - "title": "Simulation", - "advanced": [ - "name", - "sourceType" - ] - }, - "simulationStatus": { - "title": "Simulation Status", - "advanced": [] - }, - "particleAnimation": { - "title": "Plasma Animation", - "advanced": [ - "x", - "y", - "histogramBins", - "framesPerSecond", - [ - ["Minimum Filter", [ - "xMin", - "yMin", - "zMin", - "uxMin", - "uyMin", - "uzMin" - ]], - ["Maximum Filter", [ - "xMax", - "yMax", - "zMax", - "uxMax", - "uyMax", - "uzMax" - ]] - ], - "colorMap", - "notes" - ] - }, - "fieldAnimation": { - "title": "Field Animation", - "advanced": [ - "field", - "coordinate", - "mode", - "framesPerSecond", - "colorMap", - "notes" - ] - }, - "laserPreviewReport": { - "title": "Laser Preview Report", - "advanced": [ - "field", - "coordinate", - "mode", - "colorMap", - "notes" - ] - } - } -} From c50384be73776e5566207b6d063468119a6302ce Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 2 Mar 2023 21:58:16 +0000 Subject: [PATCH 03/68] create beamline and layout helper --- react/src/layout/beamline.tsx | 44 +++++++++++++++++++++++++++++++++++ react/src/layout/layouts.ts | 14 +++++++++++ 2 files changed, 58 insertions(+) create mode 100644 react/src/layout/beamline.tsx diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx new file mode 100644 index 0000000000..6c69651540 --- /dev/null +++ b/react/src/layout/beamline.tsx @@ -0,0 +1,44 @@ +import React from "react"; +import { FunctionComponent } from "react"; +import { Dependency } from "../data/dependency"; +import { SchemaLayout } from "../utility/schema"; +import { Layout, LayoutProps } from "./layout"; +import { createLayouts } from "./layouts"; + +export type BeamlineElement = { + items: SchemaLayout[], + name: string, + icon: string +} + +export type BeamlineConfig = { + elements: BeamlineElement[] +} + +export class BeamlineLayout extends Layout { + private elements: (BeamlineElement & {layouts: Layout[]})[]; + + constructor(config: BeamlineConfig) { + super(config); + this.elements = config.elements.map(e => createLayouts(e, "items")); + } + + getFormDependencies(): Dependency[] { + return []; + } + + component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { + let elementThumbnails = this.elements.map(e => { + return ( +
+ + + +
+ ) + }) + return ( + <> + ) + } +} diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index bd9f33a070..5b0746bd51 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -62,4 +62,18 @@ class LayoutWrapper { } } +export function createLayouts(obj: T, fieldName?: string): T & { layouts: Layout[] } { + fieldName = fieldName || "items"; + let v = obj[fieldName]; + if(Array.isArray(v)) { + v = v.map(x => LAYOUTS.getLayoutForSchema(x)); + } else { + v = [LAYOUTS.getLayoutForSchema(v)]; + } + return { + ...obj, + layouts: v + } +} + export const LAYOUTS = new LayoutWrapper(); From ee4bcd9cb7b4699987460c32749592569fad6bf7 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 2 Mar 2023 22:03:08 +0000 Subject: [PATCH 04/68] add shadow schema --- .../static/react-json/shadow-schema.json | 5257 +++++++++++++++++ 1 file changed, 5257 insertions(+) create mode 100644 sirepo/package_data/static/react-json/shadow-schema.json diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json new file mode 100644 index 0000000000..417c0850fc --- /dev/null +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -0,0 +1,5257 @@ +{ + "model": { + "aperture": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Aperture" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "shape": { + "displayName": "Shape", + "type": "ApertureShape", + "defaultValue": "0" + }, + "horizontalSize": { + "displayName": "Horizontal Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "verticalSize": { + "displayName": "Vertical Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "horizontalOffset": { + "displayName": "Horizontal Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "verticalOffset": { + "displayName": "Vertical Offset [mm]", + "type": "Float", + "defaultValue": 0 + } + }, + "beamline": [ + { + "models": [ + "aperture", + "crl", + "crystal", + "emptyElement", + "grating", + "lens", + "mirror", + "obstacle", + "watch", + "zonePlate" + ] + } + ], + "beamStatisticsReport": { + "epsilon": { + "displayName": "Epsilon", + "type": "Float", + "defaultValue": 0.00001 + }, + "driftDivisions": { + "displayName": "Drift Divisions", + "type": "Integer", + "defaultValue": 100, + "description": "", + "min": 1, + "max": 1000 + }, + "y1": { + "displayName": "Value to Plot 1", + "type": "BeamStatisticsParameter", + "defaultValue": "sigmax" + }, + "y2": { + "displayName": "Value to Plot 2", + "type": "BeamStatisticsParameter", + "defaultValue": "sigmaz" + }, + "y3": { + "displayName": "Value to Plot 3", + "type": "BeamStatisticsParameter", + "defaultValue": "none" + }, + "includeApertures": { + "displayName": "Include Apertures", + "type": "Boolean", + "defaultValue": "1" + }, + "k_apert_x": { + "displayName": "X Aperture Factor", + "type": "Float", + "defaultValue": 0.62, + "description": "Ratio of RMS width of the Gaussian aperture to the hard edge half aperture size" + }, + "k_apert_y": { + "displayName": "Y Aperture Factor", + "type": "Float", + "defaultValue": 0.62, + "description": "Ratio of RMS height of the Gaussian aperture to the hard edge half aperture size" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "bendingMagnet": { + "ph1": { + "displayName": "Minimum Energy [eV]", + "type": "Float", + "defaultValue": 11160 + }, + "ph2": { + "displayName": "Maximum Energy [eV]", + "type": "Float", + "defaultValue": 0 + }, + "r_magnet": { + "displayName": "Magnet Radius [m]", + "type": "Float" + }, + "fdistr": { + "displayName": "Calculation Mode", + "type": "BendingMagnetMode" + }, + "calculateFieldMethod": { + "displayName": "Compute Field/Radius", + "type": "ComputeFieldMethod", + "defaultValue": "radius" + }, + "magneticField": { + "displayName": "Magnetic Field [T]", + "type": "Float" + } + }, + "crl": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "CRL" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "numberOfLenses": { + "displayName": "Number of Lenses", + "type": "Integer", + "defaultValue": 3 + }, + "numberOfEmptySlots": { + "displayName": "Number of Empty Slots", + "type": "Integer", + "defaultValue": 0 + }, + "pilingThickness": { + "displayName": "Piling Thickness [mm]", + "type": "Float", + "defaultValue": 0.625 + }, + "focalDistance": { + "displayName": "Distance Last Lens interface-Image Plane (Q) [m]", + "type": "Float", + "defaultValue": 1.8 + }, + "fhit_c": { + "displayName": "Lens Dimensions", + "type": "ElementDimensions", + "defaultValue": "0" + }, + "lensDiameter": { + "displayName": "Lens Diameter [mm]", + "type": "Float", + "defaultValue": 0.5 + }, + "fmirr": { + "displayName": "Surface Shape", + "type": "LensShape", + "defaultValue": "5" + }, + "rmirr": { + "displayName": "Curvature Radius [mm]", + "type": "Float", + "defaultValue": 0.3 + }, + "lensThickness": { + "displayName": "Lens Thickness [mm]", + "type": "Float", + "defaultValue": 0.0625 + }, + "useCCC": { + "displayName": "Use C.C.C. (conical shape)", + "type": "Boolean", + "defaultValue": "0" + }, + "initialCurvature": { + "displayName": "Initial curvature (1st surface)", + "type": "ElementCurvature", + "defaultValue": "0" + }, + "fcyl": { + "displayName": "Cylindrical", + "type": "Boolean", + "defaultValue": "1" + }, + "cil_ang": { + "displayName": "Cylinder Angle from X Axis [deg]", + "type": "CylindricalAngle", + "defaultValue": "0.0" + }, + "refractionIndex": { + "displayName": "Refraction Index", + "type": "Float", + "defaultValue": 0.9999972289735028 + }, + "attenuationCoefficient": { + "displayName": "Attenuation Coefficient [cm-1]", + "type": "Float", + "defaultValue": 24.37099514505769 + } + }, + "crystal": { + "offx": { + "displayName": "X Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "offy": { + "displayName": "Y Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "offz": { + "displayName": "Z Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "x_rot": { + "displayName": "X Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "y_rot": { + "displayName": "Y Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "z_rot": { + "displayName": "Z Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Crystal" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "fmirr": { + "displayName": "Crystal Shape", + "type": "ElementShape", + "defaultValue": "5" + }, + "t_incidence": { + "displayName": "Incidence Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "t_reflection": { + "displayName": "Reflection Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "alpha": { + "displayName": "Orientation Angle [deg]", + "type": "OrientationAngle", + "defaultValue": 0 + }, + "fhit_c": { + "displayName": "Crystal Dimensions", + "type": "ElementDimensions", + "defaultValue": "0" + }, + "fshape": { + "displayName": "Crystal Boundary", + "type": "ElementBoundary", + "defaultValue": "1" + }, + "halfWidthX1": { + "displayName": "Half-width +X [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfWidthX2": { + "displayName": "Half-width -X [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfLengthY1": { + "displayName": "Half-length +Y [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfLengthY2": { + "displayName": "Half-length -Y [mm]", + "type": "Float", + "defaultValue": 0 + }, + "externalOutlineMajorAxis": { + "displayName": "Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "externalOutlineMinorAxis": { + "displayName": "Length (Y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "internalOutlineMajorAxis": { + "displayName": "Hole Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "internalOutlineMinorAxis": { + "displayName": "Hole Length (Y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "f_ext": { + "displayName": "Surface Type", + "type": "SurfaceType", + "defaultValue": "0" + }, + "f_default": { + "displayName": "Focii Placed at Continuation Planes?", + "type": "Boolean", + "defaultValue": "1" + }, + "ssour": { + "displayName": "Distance From Source To Crystal Center [m]", + "type": "Float", + "defaultValue": 0.01 + }, + "simag": { + "displayName": "Distance From Crystal Center to Second Focus [m]", + "type": "Float", + "defaultValue": 0.03 + }, + "theta": { + "displayName": "Incidence Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "rmirr": { + "displayName": "Spherical Radius [mm]", + "type": "Float", + "defaultValue": 16.551 + }, + "f_convex": { + "displayName": "Surface Curvature", + "type": "ElementCurvature", + "defaultValue": "0" + }, + "fcyl": { + "displayName": "Cylindrical", + "type": "Boolean", + "defaultValue": "1" + }, + "cil_ang": { + "displayName": "Cylinder Angle from X Axis [deg]", + "type": "Float", + "defaultValue": 0 + }, + "r_maj": { + "displayName": "Torus Major Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "r_min": { + "displayName": "Torus Minor Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "f_torus": { + "displayName": "Torus Pole Location", + "type": "TorusPoleLocation", + "defaultValue": "0" + }, + "f_side": { + "displayName": "Focus Location", + "type": "ParaboloidFocusLocation", + "defaultValue": "0" + }, + "param": { + "displayName": "Paraboloid Parameter [mm]", + "type": "Float", + "defaultValue": 0 + }, + "axmaj": { + "displayName": "Semi-major Axis [m]", + "type": "Float", + "defaultValue": 0 + }, + "axmin": { + "displayName": "Semi-minor Axis [m]", + "type": "Float", + "defaultValue": 0 + }, + "ell_the": { + "displayName": "Angle Between Semi-major Axis and Pole [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "f_central": { + "displayName": "Autotune Crystal", + "type": "Boolean", + "defaultValue": "1" + }, + "f_phot_cent": { + "displayName": "Autotune Units", + "type": "AutotuneUnites", + "defaultValue": "0" + }, + "phot_cent": { + "displayName": "Autotune Photon Energy [eV]", + "type": "Float", + "defaultValue": 10000 + }, + "r_lambda": { + "displayName": "Autotune Wavelength [Å]", + "type": "Float", + "defaultValue": 5000 + }, + "f_refrac": { + "displayName": "Light Propagation", + "type": "LightPropagation", + "defaultValue": "0" + }, + "f_mosaic": { + "displayName": "Mosaic Crystal", + "type": "Boolean", + "defaultValue": "1" + }, + "mosaic_seed": { + "displayName": "Mosaic Seed", + "type": "Integer", + "defaultValue": 4732094 + }, + "spread_mos": { + "displayName": "Mosaic Spread FWHM [deg]", + "type": "Float", + "defaultValue": 0.4 + }, + "f_bragg_a": { + "displayName": "Asymmetric Cut", + "type": "Boolean", + "defaultValue": "0" + }, + "a_bragg": { + "displayName": "Plane angle [deg]", + "type": "Float", + "defaultValue": 0 + }, + "order": { + "displayName": "Diffraction Order, Negative Inside", + "type": "Float", + "defaultValue": 0 + }, + "thickness": { + "displayName": "Crystal Thickness [m]", + "type": "Float", + "defaultValue": 0.01 + }, + "f_johansson": { + "displayName": "Johansson Geometry", + "type": "Boolean", + "defaultValue": "0" + }, + "r_johansson": { + "displayName": "Johansson Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "braggMaterial": { + "displayName": "", + "type": "CrystalMaterial", + "defaultValue": "Si" + }, + "braggMillerH": { + "displayName": "h", + "type": "MillerIndicesRange", + "defaultValue": "1" + }, + "braggMillerK": { + "displayName": "k", + "type": "MillerIndicesRange", + "defaultValue": "1" + }, + "braggMillerL": { + "displayName": "l", + "type": "MillerIndicesRange", + "defaultValue": "1" + }, + "braggTemperaturFactor": { + "displayName": "Temperature Factor", + "type": "Float", + "defaultValue": 1 + }, + "braggMinEnergy": { + "displayName": "Minimum Energy [eV]", + "type": "Float", + "defaultValue": 5000 + }, + "braggMaxEnergy": { + "displayName": "Maximum Energy [eV]", + "type": "Float", + "defaultValue": 55000 + }, + "braggEnergyStep": { + "displayName": "Energy Step [eV]", + "type": "Float", + "defaultValue": 100 + } + }, + "electronBeam": { + "bener": { + "displayName": "Beam Energy [GeV]", + "type": "Float" + }, + "sigmax": { + "displayName": "X Sigma [µm]", + "type": "Float" + }, + "sigmaz": { + "displayName": "Z Sigma [µm]", + "type": "Float" + }, + "epsi_x": { + "displayName": "X Emittance [nrad]", + "type": "Float" + }, + "epsi_z": { + "displayName": "Z Emittance [nrad]", + "type": "Float" + }, + "epsi_dx": { + "displayName": "X Distance From Waist [m]", + "type": "Float" + }, + "epsi_dz": { + "displayName": "Z Distance From Waist [m]", + "type": "Float" + }, + "f_pol": { + "displayName": "Polaization Component", + "type": "PolarizationComponent", + "defaultValue": "3" + } + }, + "emptyElement": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Empty Element" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "alpha": { + "displayName": "Orientation Angle [deg]", + "type": "OrientationAngle", + "defaultValue": 0 + } + }, + "geometricSource": { + "f_color": { + "displayName": "Photon Energy Distribution", + "type": "PhotonEnergyDistribution", + "defaultValue": "3" + }, + "singleEnergyValue": { + "displayName": "Value [eV]", + "type": "Float", + "defaultValue": 1000 + }, + "ph1": { + "displayName": "Minimum Energy [eV]", + "type": "Float", + "defaultValue": 1000 + }, + "ph2": { + "displayName": "Maximum Energy [eV]", + "type": "Float" + }, + "f_polar": { + "displayName": "Polarization", + "type": "Boolean", + "defaultValue": "1" + }, + "f_coher": { + "displayName": "Coherent Beam", + "type": "Boolean", + "defaultValue": "0" + }, + "pol_angle": { + "displayName": "Phase Difference [deg]", + "type": "Float", + "defaultValue": 0 + }, + "pol_deg": { + "displayName": "Degree of Polarization [cos(phi)/(cos(phi)+sin(phi))]", + "type": "Float", + "defaultValue": 0 + }, + "fsour": { + "displayName": "Spatial Type in X-Z Plane", + "type": "SpatialType", + "defaultValue": "3" + }, + "wxsou": { + "displayName": "Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "wzsou": { + "displayName": "Height (Z) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "sigmax": { + "displayName": "Sigma X [µm]", + "type": "Float", + "defaultValue": 0 + }, + "sigmaz": { + "displayName": "Sigma Z [µm]", + "type": "Float", + "defaultValue": 0 + }, + "fdistr": { + "displayName": "Angular Distribution", + "type": "AngularDistribution", + "defaultValue": "3" + }, + "sigdix": { + "displayName": "Horizontal Sigma (X) [mrad]", + "type": "Float", + "defaultValue": 0 + }, + "sigdiz": { + "displayName": "Vertical Sigma (Z) [mrad]", + "type": "Float", + "defaultValue": 0 + }, + "cone_min": { + "displayName": "Cone Internal Half-Aperture [rad]", + "type": "Float", + "defaultValue": 0 + }, + "cone_max": { + "displayName": "Cone External Half-Aperture [rad]", + "type": "Float", + "defaultValue": 0 + }, + "fsource_depth": { + "displayName": "Depth", + "type": "SourceDepth", + "defaultValue": "3" + }, + "wysou": { + "displayName": "Source Depth (y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "sigmay": { + "displayName": "Sigma Y [µm]", + "type": "Float", + "defaultValue": 0 + } + }, + "grating": { + "offx": { + "displayName": "X Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "offy": { + "displayName": "Y Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "offz": { + "displayName": "Z Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "x_rot": { + "displayName": "X Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "y_rot": { + "displayName": "Y Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "z_rot": { + "displayName": "Z Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Grating" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "fmirr": { + "displayName": "Grating Shape", + "type": "ElementShape", + "defaultValue": "5" + }, + "t_incidence": { + "displayName": "Incidence Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "t_reflection": { + "displayName": "Reflection Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "alpha": { + "displayName": "Orientation Angle [deg]", + "type": "OrientationAngle", + "defaultValue": 0 + }, + "fhit_c": { + "displayName": "Grating Dimensions", + "type": "ElementDimensions", + "defaultValue": "0" + }, + "fshape": { + "displayName": "Grating Boundary", + "type": "ElementBoundary", + "defaultValue": "1" + }, + "halfWidthX1": { + "displayName": "Half-width +X [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfWidthX2": { + "displayName": "Half-width -X [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfLengthY1": { + "displayName": "Half-length +Y [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfLengthY2": { + "displayName": "Half-length -Y [mm]", + "type": "Float", + "defaultValue": 0 + }, + "externalOutlineMajorAxis": { + "displayName": "Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "externalOutlineMinorAxis": { + "displayName": "Length (Y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "internalOutlineMajorAxis": { + "displayName": "Hole Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "internalOutlineMinorAxis": { + "displayName": "Hole Length (Y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "f_ext": { + "displayName": "Surface Type", + "type": "SurfaceType", + "defaultValue": "0" + }, + "f_default": { + "displayName": "Focii Placed at Continuation Planes?", + "type": "Boolean", + "defaultValue": "1" + }, + "ssour": { + "displayName": "Distance From Source To Grating Center [m]", + "type": "Float", + "defaultValue": 0.01 + }, + "simag": { + "displayName": "Distance From Grating Center to Second Focus [m]", + "type": "Float", + "defaultValue": 0.03 + }, + "theta": { + "displayName": "Incidence Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "rmirr": { + "displayName": "Spherical Radius [mm]", + "type": "Float", + "defaultValue": 16.551 + }, + "f_convex": { + "displayName": "Surface Curvature", + "type": "ElementCurvature", + "defaultValue": "0" + }, + "fcyl": { + "displayName": "Cylindrical", + "type": "Boolean", + "defaultValue": "1" + }, + "cil_ang": { + "displayName": "Cylinder Angle from X Axis [deg]", + "type": "Float", + "defaultValue": 0 + }, + "r_maj": { + "displayName": "Torus Major Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "r_min": { + "displayName": "Torus Minor Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "f_torus": { + "displayName": "Torus Pole Location", + "type": "TorusPoleLocation", + "defaultValue": "0" + }, + "f_side": { + "displayName": "Focus Location", + "type": "ParaboloidFocusLocation", + "defaultValue": "0" + }, + "param": { + "displayName": "Paraboloid Parameter [mm]", + "type": "Float", + "defaultValue": 0 + }, + "axmaj": { + "displayName": "Semi-major Axis [m]", + "type": "Float", + "defaultValue": 0 + }, + "axmin": { + "displayName": "Semi-minor Axis [m]", + "type": "Float", + "defaultValue": 0 + }, + "ell_the": { + "displayName": "Angle Between Semi-major Axis and Pole [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "f_central": { + "displayName": "Autotune Grating", + "type": "Boolean", + "defaultValue": "1" + }, + "f_phot_cent": { + "displayName": "Autotune Units", + "type": "AutotuneUnites", + "defaultValue": "0" + }, + "phot_cent": { + "displayName": "Autotune Photon Energy [eV]", + "type": "Float", + "defaultValue": 10000 + }, + "r_lambda": { + "displayName": "Autotune Wavelength [Å]", + "type": "Float", + "defaultValue": 5000 + }, + "order": { + "displayName": "Diffraction Order, Negative Inside", + "type": "Float", + "defaultValue": 0 + }, + "f_ruling": { + "displayName": "Ruling Type", + "type": "RulingType", + "defaultValue": "0" + }, + "rulingDensity": { + "displayName": "Ruling Density [Lines/mm]", + "type": "Float", + "defaultValue": 0 + }, + "rulingDensityCenter": { + "displayName": "Ruling Density at Center [Lines/mm]", + "type": "Float", + "defaultValue": 0 + }, + "rulingDensityPolynomial": { + "displayName": "Ruling Density a0 [Lines/mm]", + "type": "Float", + "defaultValue": 0 + }, + "holo_r1": { + "displayName": "Entrance Slit Distance [mm]", + "type": "Float", + "defaultValue": 0 + }, + "holo_del": { + "displayName": "Entrance Slit Incidence Angle [deg]", + "type": "Float", + "defaultValue": 0 + }, + "holo_rt1": { + "displayName": "Entrance Slit Rotation Angle [deg]", + "type": "Float", + "defaultValue": 0 + }, + "holo_r2": { + "displayName": "Exit Slit Distance [mm]", + "type": "Float", + "defaultValue": 0 + }, + "holo_gam": { + "displayName": "Exit Slit Incidence Angle [deg]", + "type": "Float", + "defaultValue": 0 + }, + "holo_rt2": { + "displayName": "Exit Slit Rotation Angle [deg]", + "type": "Float", + "defaultValue": 0 + }, + "f_pw": { + "displayName": "Pattern Type", + "type": "GratingPattern", + "defaultValue": "2" + }, + "f_pw_c": { + "displayName": "Cylindrical Source", + "type": "GratingCylindricalSource", + "defaultValue": "0" + }, + "f_virtual": { + "displayName": "Source Type", + "type": "GratingSourceType", + "defaultValue": "0" + }, + "holo_w": { + "displayName": "Recording Wavelength [Å]", + "type": "Float", + "defaultValue": 0 + }, + "azim_fan": { + "displayName": "Angle From Y Axis [deg, CCW]", + "type": "Float", + "defaultValue": 0 + }, + "dist_fan": { + "displayName": "Distance From Grating Center [mm]", + "type": "Float", + "defaultValue": 0 + }, + "coma_fac": { + "displayName": "Coma Correction Factor", + "type": "Float", + "defaultValue": 0 + }, + "rul_a1": { + "displayName": "Ruling Density a1 [Lines/mm²]", + "type": "Float", + "defaultValue": 0 + }, + "rul_a2": { + "displayName": "Ruling Density a2 [Lines/mm³]", + "type": "Float", + "defaultValue": 0 + }, + "rul_a3": { + "displayName": "Ruling Density a3 [Lines/mm⁴]", + "type": "Float", + "defaultValue": 0 + }, + "rul_a4": { + "displayName": "Ruling Density a4 [Lines/mm⁵]", + "type": "Float", + "defaultValue": 0 + }, + "f_rul_abs": { + "displayName": "Density Absolute/Signed from Origin", + "type": "AbsoluteOrigin", + "defaultValue": "0" + }, + "f_mono": { + "displayName": "Monochromator Type", + "type": "GratingMonoType", + "defaultValue": "0" + }, + "f_hunt": { + "displayName": "Grating Selected", + "type": "GratingHunter", + "defaultValue": "1" + }, + "hunt_h": { + "displayName": "Distance Between Beams [mm]", + "type": "Float", + "defaultValue": 0 + }, + "hunt_l": { + "displayName": "Monochromator Length [mm]", + "type": "Float", + "defaultValue": 0 + }, + "blaze": { + "displayName": "Blaze Angle [deg]", + "type": "Float", + "defaultValue": 0 + } + }, + "histogramReport": { + "distanceFromSource": { + "displayName": "Distance From Source [m]", + "type": "Float", + "defaultValue": 0 + }, + "column": { + "displayName": "Column", + "type": "ColumnValue" + }, + "weight": { + "displayName": "Weight", + "type": "ColumnWeight", + "defaultValue": "22" + }, + "histogramBins": { + "displayName": "Number of Bins", + "type": "Integer" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "initialIntensityReport": { + "x": { + "displayName": "Value to Plot", + "type": "ColumnValue", + "defaultValue": "1" + }, + "y": { + "displayName": "Value to Plot", + "type": "ColumnValue", + "defaultValue": "3" + }, + "weight": { + "displayName": "Weight", + "type": "ColumnWeight", + "defaultValue": "22" + }, + "histogramBins": { + "displayName": "Number of Bins", + "type": "Integer", + "defaultValue": 100 + }, + "overrideSize": { + "displayName": "Override Plot Size", + "type": "Boolean", + "defaultValue": "0" + }, + "horizontalSize": { + "displayName": "Horizontal Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "verticalSize": { + "displayName": "Vertical Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "horizontalOffset": { + "displayName": "Horizontal Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "verticalOffset": { + "displayName": "Vertical Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "viridis" + }, + "aspectRatio": { + "displayName": "Aspect Ratio", + "type": "AspectRatio", + "defaultValue": "1" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "lens": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Lens" + }, + "position": { + "displayName": "Position along Optical Path [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "focal_x": { + "displayName": "Horizontal Focal Length [m]", + "type": "Float", + "defaultValue": 3 + }, + "focal_z": { + "displayName": "Vertical Focal Length [m]", + "type": "Float", + "defaultValue": 1e+23 + } + }, + "mirror": { + "offx": { + "displayName": "X Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "offy": { + "displayName": "Y Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "offz": { + "displayName": "Z Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "x_rot": { + "displayName": "X Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "y_rot": { + "displayName": "Y Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "z_rot": { + "displayName": "Z Rotation [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Mirror" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "fmirr": { + "displayName": "Mirror Shape", + "type": "ElementShape", + "defaultValue": "5" + }, + "t_incidence": { + "displayName": "Incidence Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "alpha": { + "displayName": "Orientation Angle [deg]", + "type": "OrientationAngle", + "defaultValue": 0 + }, + "fhit_c": { + "displayName": "Mirror Dimensions", + "type": "ElementDimensions", + "defaultValue": "0" + }, + "fshape": { + "displayName": "Mirror Boundary", + "type": "ElementBoundary", + "defaultValue": "1" + }, + "halfWidthX1": { + "displayName": "Half-width +X [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfWidthX2": { + "displayName": "Half-width -X [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfLengthY1": { + "displayName": "Half-length +Y [mm]", + "type": "Float", + "defaultValue": 0 + }, + "halfLengthY2": { + "displayName": "Half-length -Y [mm]", + "type": "Float", + "defaultValue": 0 + }, + "externalOutlineMajorAxis": { + "displayName": "Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "externalOutlineMinorAxis": { + "displayName": "Length (Y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "internalOutlineMajorAxis": { + "displayName": "Hole Width (X) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "internalOutlineMinorAxis": { + "displayName": "Hole Length (Y) [mm]", + "type": "Float", + "defaultValue": 0 + }, + "f_ext": { + "displayName": "Surface Type", + "type": "SurfaceType", + "defaultValue": "0" + }, + "f_default": { + "displayName": "Focii Placed at Continuation Planes?", + "type": "Boolean", + "defaultValue": "1" + }, + "ssour": { + "displayName": "Distance From Source To Mirror Center [m]", + "type": "Float", + "defaultValue": 0.01 + }, + "simag": { + "displayName": "Distance From Mirror Center to Second Focus [m]", + "type": "Float", + "defaultValue": 0.03 + }, + "theta": { + "displayName": "Incidence Angle [deg]", + "type": "Float", + "defaultValue": 35 + }, + "rmirr": { + "displayName": "Spherical Radius [mm]", + "type": "Float", + "defaultValue": 16.551 + }, + "f_convex": { + "displayName": "Surface Curvature", + "type": "ElementCurvature", + "defaultValue": "0" + }, + "fcyl": { + "displayName": "Cylindrical", + "type": "Boolean", + "defaultValue": "1" + }, + "cil_ang": { + "displayName": "Cylinder Angle from X Axis [deg]", + "type": "Float", + "defaultValue": 0 + }, + "r_maj": { + "displayName": "Torus Major Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "r_min": { + "displayName": "Torus Minor Radius [m]", + "type": "Float", + "defaultValue": 0 + }, + "f_torus": { + "displayName": "Torus Pole Location", + "type": "TorusPoleLocation", + "defaultValue": "0" + }, + "f_side": { + "displayName": "Focus Location", + "type": "ParaboloidFocusLocation", + "defaultValue": "0" + }, + "param": { + "displayName": "Paraboloid Parameter [mm]", + "type": "Float", + "defaultValue": 0 + }, + "axmaj": { + "displayName": "Semi-major Axis [m]", + "type": "Float", + "defaultValue": 0 + }, + "axmin": { + "displayName": "Semi-minor Axis [m]", + "type": "Float", + "defaultValue": 0 + }, + "ell_the": { + "displayName": "Angle Between Semi-major Axis and Pole [CCW, deg]", + "type": "Float", + "defaultValue": 0 + }, + "f_reflec": { + "displayName": "Reflectivity", + "type": "MirrorReflectivity", + "defaultValue": "0" + }, + "f_refl": { + "displayName": "File Source", + "type": "ReflectivityFileSource", + "defaultValue": "0" + }, + "f_thick": { + "displayName": "Mlayer Thickness Vary as Cosine", + "type": "Boolean", + "defaultValue": "0" + }, + "prereflElement": { + "displayName": "Element/Compound Forumula", + "type": "ReflectivityMaterial", + "defaultValue": "Rh" + }, + "prereflDensity": { + "displayName": "Density [g/m]", + "type": "Float", + "defaultValue": 0.124 + }, + "reflectivityMinEnergy": { + "displayName": "Minimum Energy [eV]", + "type": "Float", + "defaultValue": 5000 + }, + "reflectivityMaxEnergy": { + "displayName": "Maximum Energy [eV]", + "type": "Float", + "defaultValue": 55000 + }, + "prereflStep": { + "displayName": "Energy Step [eV]", + "type": "Float", + "defaultValue": 100 + }, + "mlayerSubstrateMaterial": { + "displayName": "Material Substrate", + "type": "ReflectivityMaterial", + "defaultValue": "Si" + }, + "mlayerSubstrateDensity": { + "displayName": "Density Substrate", + "type": "Float", + "defaultValue": 2.33 + }, + "mlayerEvenSublayerMaterial": { + "displayName": "Material Even Sublayer", + "type": "ReflectivityMaterial", + "defaultValue": "B4C" + }, + "mlayerEvenSublayerDensity": { + "displayName": "Density Even Sublayer", + "type": "Float", + "defaultValue": 2.4 + }, + "mlayerOddSublayerMaterial": { + "displayName": "Material Odd Sublayer", + "type": "ReflectivityMaterial", + "defaultValue": "Ru" + }, + "mlayerOddSublayerDensity": { + "displayName": "Density Odd Sublayer", + "type": "Float", + "defaultValue": 9.4 + }, + "mlayerBilayerNumber": { + "displayName": "Number of Bilayers", + "type": "Integer", + "defaultValue": 70 + }, + "mlayerBilayerThickness": { + "displayName": "Bilayer Thickness [Å]", + "type": "Float", + "defaultValue": 33.1 + }, + "mlayerGammaRatio": { + "displayName": "Gamma Ratio (t_even/(t_odd+t_even)", + "type": "Float", + "defaultValue": 0.483 + }, + "mlayerEvenRoughness": { + "displayName": "Even Layer Roughness [Å]", + "type": "Float", + "defaultValue": 3.3 + }, + "mlayerOddRoughness": { + "displayName": "Odd Layer Roughness [Å]", + "type": "Float", + "defaultValue": 3.1 + } + }, + "obstacle": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Obstacle" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "shape": { + "displayName": "Shape", + "type": "ApertureShape", + "defaultValue": "0" + }, + "horizontalSize": { + "displayName": "Horizontal Size [mm]", + "type": "Float", + "defaultValue": 1 + }, + "verticalSize": { + "displayName": "Vertical Size [mm]", + "type": "Float", + "defaultValue": 1 + }, + "horizontalOffset": { + "displayName": "Horizontal Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "verticalOffset": { + "displayName": "Vertical Offset [mm]", + "type": "Float", + "defaultValue": 0 + } + }, + "plotXYReport": { + "x": { + "displayName": "Value to Plot", + "type": "ColumnValue", + "defaultValue": "1" + }, + "y": { + "displayName": "Value to Plot", + "type": "ColumnValue", + "defaultValue": "3" + }, + "weight": { + "displayName": "Weight", + "type": "ColumnWeight", + "defaultValue": "22" + }, + "histogramBins": { + "displayName": "Number of Bins", + "type": "Integer", + "defaultValue": 100 + }, + "overrideSize": { + "displayName": "Override Plot Size", + "type": "Boolean", + "defaultValue": "0" + }, + "horizontalSize": { + "displayName": "Horizontal Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "verticalSize": { + "displayName": "Vertical Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "horizontalOffset": { + "displayName": "Horizontal Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "verticalOffset": { + "displayName": "Vertical Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "viridis" + }, + "aspectRatio": { + "displayName": "Aspect Ratio", + "type": "AspectRatio", + "defaultValue": "1" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + }, + "distanceFromSource": { + "displayName": "Distance From Source [m]", + "type": "Float", + "defaultValue": 0 + } + }, + "rayFilter": { + "f_bound_sour": { + "displayName": "Optimize Source", + "type": "BoundSource", + "defaultValue": "0" + }, + "distance": { + "displayName": "Distance [m]", + "type": "Float", + "defaultValue": 0.000001 + }, + "x1": { + "displayName": "X Minimum [mm]", + "type": "Float", + "defaultValue": -10000000000000000 + }, + "x2": { + "displayName": "X Maximum [mm]", + "type": "Float", + "defaultValue": 10000000000000000 + }, + "z1": { + "displayName": "Z Minimum [mm]", + "type": "Float", + "defaultValue": -10000000000000000 + }, + "z2": { + "displayName": "Z Maximum [mm]", + "type": "Float", + "defaultValue": 10000000000000000 + } + }, + "simulation": { + "sourceType": { + "displayName": "Source Type", + "type": "SourceType", + "defaultValue": "bendingMagnet" + }, + "npoint": { + "displayName": "Number of Rays", + "type": "Integer", + "defaultValue": 5000 + }, + "istar1": { + "displayName": "Seed", + "type": "Integer", + "defaultValue": 567656 + } + }, + "sourceDivergence": { + "hdiv1": { + "displayName": "Horizontal Divergence +X [mrad]", + "type": "Float", + "defaultValue": 0 + }, + "hdiv2": { + "displayName": "Horizontal Divergence -X [mrad]", + "type": "Float", + "defaultValue": 0 + }, + "vdiv1": { + "displayName": "Vertical Divergence +Z [mrad]", + "type": "Float", + "defaultValue": 0.06 + }, + "vdiv2": { + "displayName": "Vertical Divergence -Z [mrad]", + "type": "Float", + "defaultValue": 0.06 + } + }, + "undulator": { + "k_horizontal": { + "displayName": "Horizontal Deflecting Parameter (K)", + "type": "Float", + "defaultValue": 0 + }, + "k_vertical": { + "displayName": "Vertical Deflecting Parameter (K)", + "type": "Float", + "defaultValue": 0 + }, + "period": { + "displayName": "Period [mm]", + "type": "Float", + "defaultValue": 20, + "description": "", + "min": 1e-99 + }, + "length": { + "displayName": "Length [m]", + "type": "Float", + "defaultValue": 3, + "description": "", + "min": 1e-99 + }, + "emin": { + "displayName": "Minimum Photon Energy [eV]", + "type": "Float", + "defaultValue": 10000 + }, + "emax": { + "displayName": "Maximum Photon Energy [eV]", + "type": "Float", + "defaultValue": 11000 + }, + "ng_e": { + "displayName": "Photon energy scan points", + "type": "Integer", + "defaultValue": 11 + }, + "maxangle": { + "displayName": "Maximum radiation semiaperture [µrad]", + "type": "Float", + "defaultValue": 50 + }, + "ng_t": { + "displayName": "Points in angle theta", + "type": "Integer", + "defaultValue": 31 + }, + "ng_p": { + "displayName": "Points in angle phi", + "type": "Integer", + "defaultValue": 21 + }, + "ng_j": { + "displayName": "Points in electron trajectory", + "type": "Integer", + "defaultValue": 20 + }, + "flag_size": { + "displayName": "Radiation Size", + "type": "UndulatorRadiationSize", + "defaultValue": "1" + }, + "f_coher": { + "displayName": "Coherent Beam", + "type": "Boolean", + "defaultValue": "0" + }, + "energy_harmonic": { + "displayName": "Energy Harmonic", + "type": "Harmonic", + "defaultValue": 1 + }, + "select_energy": { + "displayName": "Select Photon Energy", + "type": "SelectPhotonEnergy", + "defaultValue": "harmonic" + }, + "photon_energy": { + "displayName": "Photon Energy [eV]", + "type": "Float", + "defaultValue": 10000 + } + }, + "undulatorBeam": { + "energy": { + "displayName": "Energy [GeV]", + "type": "Float", + "defaultValue": 1 + }, + "energy_spread": { + "displayName": "Energy Spread", + "type": "Float", + "defaultValue": 0 + }, + "current": { + "displayName": "Current [A]", + "type": "Float", + "defaultValue": 0.1 + }, + "number_of_bunches": { + "displayName": "Number of Bunches", + "type": "Integer", + "defaultValue": 1 + }, + "emittance_x": { + "displayName": "Horizontal Emittance [nm]", + "type": "Float", + "defaultValue": 0.55 + }, + "beta_x": { + "displayName": "Horizontal Beta [m]", + "type": "Float", + "defaultValue": 1.84, + "description": 1e-99 + }, + "alpha_x": { + "displayName": "Horizontal Alpha [rad]", + "type": "Float", + "defaultValue": 0 + }, + "eta_x": { + "displayName": "Horizontal Dispersion [m]", + "type": "Float", + "defaultValue": 0 + }, + "etap_x": { + "displayName": "Horizontal Dispersion Derivative [rad]", + "type": "Float", + "defaultValue": 0 + }, + "emittance_y": { + "displayName": "Vertical Emittance [nm]", + "type": "Float", + "defaultValue": 0.008 + }, + "beta_y": { + "displayName": "Vertical Beta [m]", + "type": "Float", + "defaultValue": 1.17, + "description": 1e-99 + }, + "alpha_y": { + "displayName": "Vertical Alpha [rad]", + "type": "Float", + "defaultValue": 0 + }, + "eta_y": { + "displayName": "Vertical Dispersion [m]", + "type": "Float", + "defaultValue": 0 + }, + "etap_y": { + "displayName": "Vertical Dispersion Derivative [rad]", + "type": "Float", + "defaultValue": 0 + } + }, + "watch": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Watchpoint" + }, + "position": { + "displayName": "Nominal Position [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + } + }, + "watchpointReport": { + "x": { + "displayName": "Value to Plot", + "type": "ColumnValue", + "defaultValue": "1" + }, + "y": { + "displayName": "Value to Plot", + "type": "ColumnValue", + "defaultValue": "3" + }, + "weight": { + "displayName": "Weight", + "type": "ColumnWeight", + "defaultValue": "22" + }, + "histogramBins": { + "displayName": "Number of Bins", + "type": "Integer", + "defaultValue": 100 + }, + "overrideSize": { + "displayName": "Override Plot Size", + "type": "Boolean", + "defaultValue": "0" + }, + "horizontalSize": { + "displayName": "Horizontal Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "verticalSize": { + "displayName": "Vertical Size [mm]", + "type": "Float", + "defaultValue": 10 + }, + "horizontalOffset": { + "displayName": "Horizontal Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "verticalOffset": { + "displayName": "Vertical Offset [mm]", + "type": "Float", + "defaultValue": 0 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "viridis" + }, + "aspectRatio": { + "displayName": "Aspect Ratio", + "type": "AspectRatio", + "defaultValue": "1" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "wiggler": { + "ph1": { + "displayName": "Minimum Energy [eV]", + "type": "Float", + "defaultValue": 20000 + }, + "ph2": { + "displayName": "Maximum Energy [eV]", + "type": "Float", + "defaultValue": 20020 + }, + "b_from": { + "displayName": "Magnetic Field Definition", + "type": "MagneticFieldType", + "defaultValue": "0" + }, + "nPer": { + "displayName": "Number of Periods", + "type": "Integer", + "defaultValue": 12 + }, + "per": { + "displayName": "ID Period [m]", + "type": "Float", + "defaultValue": 0.125 + }, + "kValue": { + "displayName": "K Value", + "type": "Float", + "defaultValue": 14 + }, + "trajFile": { + "displayName": "Trajectory File", + "type": "InputFile" + }, + "shift_x_flag": { + "displayName": "Shift Transversal Velocity", + "type": "BeamShift", + "defaultValue": "0" + }, + "shift_x_value": { + "displayName": "Value", + "type": "Float", + "defaultValue": 0 + }, + "shift_betax_flag": { + "displayName": "Shift Transversal Coordinate", + "type": "BeamShift", + "defaultValue": "0" + }, + "shift_betax_value": { + "displayName": "Value", + "type": "Float", + "defaultValue": 0 + } + }, + "zonePlate": { + "title": { + "displayName": "Element Name", + "type": "String", + "defaultValue": "Zone Plate" + }, + "position": { + "displayName": "Position along Optical Path [m]", + "type": "Float" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "type": { + "displayName": "Type", + "type": "String" + }, + "zone_plate_type": { + "displayName": "Zone Plate Type", + "type": "ZonePlateType", + "defaultValue": "0" + }, + "width_coating": { + "displayName": "Coating Width [nm]", + "type": "Float", + "defaultValue": 20 + }, + "height": { + "displayName": "Height [mm]", + "type": "Float", + "defaultValue": 4 + }, + "diameter": { + "displayName": "Diameter [mm]", + "type": "Float", + "defaultValue": 4 + }, + "b_min": { + "displayName": "Outer Zone Width [µm]", + "type": "Float", + "defaultValue": 10 + }, + "zone_plate_material": { + "displayName": "Material", + "type": "ReflectivityMaterial", + "defaultValue": "Au" + }, + "template_material": { + "displayName": "Template Material", + "type": "ReflectivityMaterial", + "defaultValue": "SiO2" + }, + "n_points": { + "displayName": "Sampling Points", + "type": "Integer", + "defaultValue": 5000 + }, + "last_index": { + "displayName": "Last Index of Focal Image", + "type": "Integer", + "defaultValue": 100 + } + } + }, + "type": { + "AbsoluteOrigin": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Absolute" + ], + [ + "1", + "Origin" + ] + ] + } + }, + "AngularDistribution": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Flat" + ], + [ + "2", + "Uniform" + ], + [ + "3", + "Gaussian" + ], + [ + "5", + "Conical" + ] + ] + } + }, + "ApertureShape": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Rectangular" + ], + [ + "1", + "Ellipse" + ] + ] + } + }, + "AutotuneUnites": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "eV" + ], + [ + "1", + "Angstroms" + ] + ] + } + }, + "BeamShift": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "No shift" + ], + [ + "1", + "Half excursion" + ], + [ + "2", + "Minimum" + ], + [ + "3", + "Maximum" + ], + [ + "4", + "Value at zero" + ], + [ + "5", + "User value" + ] + ] + } + }, + "BeamStatisticsParameter": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "none", + "None" + ], + [ + "angxz", + "X-Z Plane Rotation Angle (angxz)" + ], + [ + "angxpzp", + "X'-Z' Plane Rotation Angle (angxpzp)" + ], + [ + "emit_x", + "Horizontal Emittance (emit_x)" + ], + [ + "emit_z", + "Vertical Emittance (emit_z)" + ], + [ + "sigmax", + "Horizontal RMS Beam Size (sigmax)" + ], + [ + "sigdix", + "Horizontal RMS Divergence (sigdix)" + ], + [ + "sigxdix", + " Horizontal Phase Space Cross Term (sigxdix)" + ], + [ + "sigmaz", + "Vertical RMS Beam Size (sigmaz)" + ], + [ + "sigdiz", + "Vertical RMS Divergence (sigdiz)" + ], + [ + "sigzdiz", + " Vertical Phase Space Cross Term (sigzdiz)" + ], + [ + "sigmaxz", + "Spatial Cross Term (sigmaxz)" + ], + [ + "sigmaxpzp", + " Angular Divergence Cross Term (sigmaxpzp)" + ], + [ + "x", + "Horizontal Centroid (x)" + ], + [ + "xp", + "Horizontal Angular Centroid (xp)" + ], + [ + "z", + "Vertical Centroid (z)" + ], + [ + "zp", + "Vertical Angular Centroid (zp)" + ], + [ + "xi_x", + "Horizontal Coherence Length (xi_x)" + ], + [ + "xi_z", + "Vertical Coherence Length (xi_z)" + ] + ] + } + }, + "BendingMagnetMode": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "4", + "Synchrotron" + ], + [ + "6", + "Exact Synchrotron" + ] + ] + } + }, + "BoundSource": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "No Filter" + ], + [ + "2", + "Aperture" + ] + ] + } + }, + "ColumnValue": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "X" + ], + [ + "2", + "Y" + ], + [ + "3", + "Z" + ], + [ + "4", + "X'" + ], + [ + "5", + "Y'" + ], + [ + "6", + "Z'" + ], + [ + "7", + "Es X" + ], + [ + "8", + "Es Y" + ], + [ + "9", + "Es Z" + ], + [ + "10", + "Ray Flag" + ], + [ + "11", + "Energy" + ], + [ + "12", + "Ray Index" + ], + [ + "13", + "Optical Path" + ], + [ + "14", + "Phase s" + ], + [ + "15", + "Phase p" + ], + [ + "16", + "Ep X" + ], + [ + "17", + "Ep Y" + ], + [ + "18", + "Ep Z" + ], + [ + "19", + "Wavelength" + ], + [ + "20", + "R = sqrt(X² + Y² + Z²)" + ], + [ + "21", + "Theta (angle from Y axis)" + ], + [ + "22", + "Magnitude = |Es| + |Ep|" + ], + [ + "23", + "Total Intensity = |Es|² + |Ep|²" + ], + [ + "24", + "S Intensity = |Es|²" + ], + [ + "25", + "P Intensity = |Ep|²" + ], + [ + "26", + "|K|" + ], + [ + "27", + "K X" + ], + [ + "28", + "K Y" + ], + [ + "29", + "K Z" + ], + [ + "30", + "S0-stokes = |Ep|² + |Es|²" + ], + [ + "31", + "S1-stokes = |Ep|² - |Es|²" + ], + [ + "32", + "S2-stokes = 2|Es||Ep|cos(Phase s-Phase p)" + ], + [ + "33", + "S3-stokes = 2|Es||Ep|sin(Phase s-Phase p)" + ] + ] + } + }, + "ColumnWeight": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "No Weight" + ], + [ + "1", + "X" + ], + [ + "2", + "Y" + ], + [ + "3", + "Z" + ], + [ + "4", + "X'" + ], + [ + "5", + "Y'" + ], + [ + "6", + "Z'" + ], + [ + "7", + "Es X" + ], + [ + "8", + "Es Y" + ], + [ + "9", + "Es Z" + ], + [ + "10", + "Ray Flag" + ], + [ + "11", + "Energy" + ], + [ + "12", + "Ray Index" + ], + [ + "13", + "Optical Path" + ], + [ + "14", + "Phase s" + ], + [ + "15", + "Phase p" + ], + [ + "16", + "Ep X" + ], + [ + "17", + "Ep Y" + ], + [ + "18", + "Ep Z" + ], + [ + "19", + "Wavelength" + ], + [ + "20", + "R = sqrt(X² + Y² + Z²)" + ], + [ + "21", + "Theta (angle from Y axis)" + ], + [ + "22", + "Magnitude = |Es| + |Ep|" + ], + [ + "23", + "Total Intensity = |Es|² + |Ep|²" + ], + [ + "24", + "S Intensity = |Es|²" + ], + [ + "25", + "P Intensity = |Ep|²" + ], + [ + "26", + "|K|" + ], + [ + "27", + "K X" + ], + [ + "28", + "K Y" + ], + [ + "29", + "K Z" + ], + [ + "30", + "S0-stokes = |Ep|² + |Es|²" + ], + [ + "31", + "S1-stokes = |Ep|² - |Es|²" + ], + [ + "32", + "S2-stokes = 2|Es||Ep|cos(Phase s-Phase p)" + ], + [ + "33", + "S3-stokes = 2|Es||Ep|sin(Phase s-Phase p)" + ] + ] + } + }, + "ComputeFieldMethod": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "radius", + "From Magnet Radius" + ], + [ + "field", + "From Magnetic Field" + ] + ] + } + }, + "CrystalMaterial": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "AlphaAlumina", + "AlphaAlumina" + ], + [ + "AlphaQuartz", + "AlphaQuartz" + ], + [ + "Aluminum", + "Aluminum" + ], + [ + "Be", + "Be" + ], + [ + "Beryl", + "Beryl" + ], + [ + "Copper", + "Copper" + ], + [ + "CsCl", + "CsCl" + ], + [ + "CsF", + "CsF" + ], + [ + "Diamond", + "Diamond" + ], + [ + "GaAs", + "GaAs" + ], + [ + "GaP", + "GaP" + ], + [ + "GaSb", + "GaSb" + ], + [ + "Ge", + "Ge" + ], + [ + "Gold", + "Gold" + ], + [ + "Graphite", + "Graphite" + ], + [ + "InAs", + "InAs" + ], + [ + "InP", + "InP" + ], + [ + "InSb", + "InSb" + ], + [ + "Iron", + "Iron" + ], + [ + "KAP", + "KAP" + ], + [ + "KCl", + "KCl" + ], + [ + "KTP", + "KTP" + ], + [ + "LaB6", + "LaB6" + ], + [ + "LaB6_NIST", + "LaB6_NIST" + ], + [ + "LiF", + "LiF" + ], + [ + "LiNbO3", + "LiNbO3" + ], + [ + "Muscovite", + "Muscovite" + ], + [ + "NaCl", + "NaCl" + ], + [ + "PET", + "PET" + ], + [ + "Platinum", + "Platinum" + ], + [ + "RbAP", + "RbAP" + ], + [ + "Sapphire", + "Sapphire" + ], + [ + "Si", + "Si" + ], + [ + "Si2", + "Si2" + ], + [ + "SiC", + "SiC" + ], + [ + "Si_NIST", + "Si_NIST" + ], + [ + "Titanium", + "Titanium" + ], + [ + "TlAP", + "TlAP" + ] + ] + } + }, + "CylindricalAngle": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0.0", + "0 (Meridional)" + ], + [ + "90.0", + "90 (Sagittal)" + ] + ] + } + }, + "ElementBoundary": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Rectangular" + ], + [ + "2", + "Ellipse" + ], + [ + "3", + "Ellipse with Hole" + ] + ] + } + }, + "ElementCurvature": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Concave" + ], + [ + "1", + "Convex" + ] + ] + } + }, + "ElementDimensions": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Infinite" + ], + [ + "1", + "Finite" + ] + ] + } + }, + "ElementShape": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "2", + "Ellipsoid" + ], + [ + "7", + "Hyperboloid" + ], + [ + "4", + "Paraboloid" + ], + [ + "5", + "Plane" + ], + [ + "1", + "Spherical" + ], + [ + "3", + "Toroidal" + ] + ] + } + }, + "GratingCylindricalSource": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Spherical/Spherical" + ], + [ + "1", + "Cylindrical/Spherical" + ], + [ + "2", + "Spherical/Cylindrical" + ], + [ + "3", + "Cylindrical/Cylindrical" + ] + ] + } + }, + "GratingHunter": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "First" + ], + [ + "2", + "Second" + ] + ] + } + }, + "GratingMonoType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "TGM/Seya" + ], + [ + "1", + "ERG" + ], + [ + "2", + "Constant Incidence Angle" + ], + [ + "3", + "Constant Diffraction Angle" + ], + [ + "4", + "Hunter" + ] + ] + } + }, + "GratingPattern": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Spherical/Spherical" + ], + [ + "1", + "Plane/Spherical" + ], + [ + "2", + "Spherical/Plane" + ], + [ + "3", + "Plane/Plane" + ] + ] + } + }, + "GratingSourceType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Real/Real" + ], + [ + "1", + "Real/Virtual" + ], + [ + "2", + "Virtual/Real" + ], + [ + "3", + "Real/Real" + ] + ] + } + }, + "Harmonic": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "1" + ], + [ + "3", + "3" + ], + [ + "5", + "5" + ], + [ + "7", + "7" + ], + [ + "9", + "9" + ], + [ + "11", + "11" + ], + [ + "13", + "13" + ], + [ + "15", + "15" + ], + [ + "17", + "17" + ] + ] + } + }, + "LensShape": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Spherical" + ], + [ + "4", + "Paraboloid" + ], + [ + "5", + "Plane" + ] + ] + } + }, + "LightPropagation": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Reflector" + ], + [ + "1", + "Refractor" + ] + ] + } + }, + "MagneticFieldType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + " kValue (deflecting parameters)" + ], + [ + "1", + "File with the magnetic field (y[m], B[T])" + ], + [ + "2", + "File with the magnetic field harmonics (n, Bn[T])" + ] + ] + } + }, + "MillerIndicesRange": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "0" + ], + [ + "1", + "1" + ], + [ + "2", + "2" + ], + [ + "3", + "3" + ], + [ + "4", + "4" + ], + [ + "5", + "5" + ], + [ + "6", + "6" + ], + [ + "7", + "7" + ], + [ + "8", + "8" + ], + [ + "9", + "9" + ], + [ + "10", + "10" + ], + [ + "-1", + "-1" + ], + [ + "-2", + "-2" + ], + [ + "-3", + "-3" + ], + [ + "-4", + "-4" + ], + [ + "-5", + "-5" + ], + [ + "-6", + "-6" + ], + [ + "-7", + "-7" + ], + [ + "-8", + "-8" + ], + [ + "-9", + "-9" + ], + [ + "-10", + "-10" + ] + ] + } + }, + "MirrorReflectivity": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "No Reflectivity Dependence" + ], + [ + "1", + "Full Polarization Dependence" + ], + [ + "2", + "No Polarization Dependence (Scalar)" + ] + ] + } + }, + "OrientationAngle": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "0" + ], + [ + "90", + "90" + ], + [ + "180", + "180" + ], + [ + "270", + "270" + ] + ] + } + }, + "ParaboloidFocusLocation": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Image" + ], + [ + "1", + "Source" + ] + ] + } + }, + "PhotonEnergyDistribution": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Single Line" + ], + [ + "3", + "Uniform" + ] + ] + } + }, + "PolarizationComponent": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Only Parallel" + ], + [ + "2", + "Only Perpendicular" + ], + [ + "3", + "Total" + ] + ] + } + }, + "ReflectivityFileSource": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "PREREFL" + ], + [ + "2", + "PRE_MLAYER" + ] + ] + } + }, + "RulingType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Constant on X-Y Plane" + ], + [ + "1", + "Constant on Mirror Surface" + ], + [ + "2", + "Holographic" + ], + [ + "3", + "Fan Type" + ], + [ + "5", + "Polynomial Line Density" + ] + ] + } + }, + "SelectPhotonEnergy": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "harmonic", + "From Harmonic" + ], + [ + "single", + "Single Photon Energy" + ], + [ + "range", + "Photon Energy Range" + ] + ] + } + }, + "SourceDepth": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "No Depth" + ], + [ + "2", + "Uniform" + ], + [ + "3", + "Gaussian" + ] + ] + } + }, + "SourceType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "bendingMagnet", + "Bending Magnet" + ], + [ + "geometricSource", + "Geometric Source" + ], + [ + "undulator", + "Undulator" + ], + [ + "wiggler", + "Wiggler" + ] + ] + } + }, + "SpatialType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Point" + ], + [ + "1", + "Rectangle" + ], + [ + "2", + "Ellipse" + ], + [ + "3", + "Gaussian" + ] + ] + } + }, + "SurfaceType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Calculated" + ], + [ + "1", + "User Defined" + ] + ] + } + }, + "TorusPoleLocation": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Lower/Outer (Concave/Concave)" + ], + [ + "1", + "Lower/Inner (Concave/Convex)" + ], + [ + "2", + "Upper/Inner (Convex/Concave)" + ], + [ + "3", + "Upper/Outer (Convex/Convex)" + ] + ] + } + }, + "UndulatorRadiationSize": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Point" + ], + [ + "1", + "Gaussian" + ], + [ + "2", + "FT(Divergences)" + ] + ] + } + }, + "ZonePlateType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "0", + "Ordinary" + ], + [ + "1", + "Zone-Doubled" + ], + [ + "2", + "Zone-Filled" + ] + ] + } + } + }, + "view": [ + { + "layout": "navbarModalButton", + "config": { + "name": "simulationRenameNavButton", + "title": "$(simulation.name)", + "icon": "faPencil", + "modal": { + "title": "Simulation", + "items": [ + { + "layout": "fieldList", + "config": { + "name": "simulation", + "fields": [ + "simulation.name" + ] + } + } + ] + } + } + }, + { + "layout": "navTabs", + "tabs": [ + { + "name": "Source", + "items": [ + { + "layout": "panel", + "config": { + "title": "Geometric Source", + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "geometricSource.fsour", + "geometricSource.wxsou", + "geometricSource.wzsou", + "geometricSource.sigmax", + "geometricSource.sigmaz" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Geometry Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "geometricSource.fsour", + "geometricSource.wxsou", + "geometricSource.wzsou", + "geometricSource.sigmax", + "geometricSource.sigmaz", + "geometricSource.fdistr" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Divergence +X [mrad]", + "fields": [ + "sourceDivergence.hdiv1", + "sourceDivergence.vdiv1" + ] + }, + { + "label": "Horizontal Divergence -X [mrad]", + "fields": [ + "sourceDivergence.hdiv2", + "sourceDivergence.vdiv2" + ] + }, + { + "label": "Horizontal Sigma (X) [mrad]", + "fields": [ + "geometricSource.sigdix", + "geometricSource.sigdiz" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "geometricSource.cone_min", + "geometricSource.cone_max", + "geometricSource.fsource_depth", + "geometricSource.wysou", + "geometricSource.sigmay" + ] + } + } + ] + }, + { + "name": "Energy/Polarization Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "geometricSource.f_color", + "geometricSource.singleEnergyValue", + "geometricSource.ph1", + "geometricSource.ph2", + "geometricSource.f_polar", + "geometricSource.f_coher", + "geometricSource.pol_angle", + "geometricSource.pol_deg" + ] + } + } + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "geometricSource" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "bendingMagnet.ph1", + "bendingMagnet.ph2", + "electronBeam.bener" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "bendingMagnet.ph1", + "bendingMagnet.ph2" + ] + } + } + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "electronBeam.bener", + "electronBeam.f_pol" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Z" + ], + "rows": [ + { + "label": "X Sigma [µm]", + "fields": [ + "electronBeam.sigmax", + "electronBeam.sigmaz" + ] + }, + { + "label": "X Emittance [nrad]", + "fields": [ + "electronBeam.epsi_x", + "electronBeam.epsi_z" + ] + }, + { + "label": "X Distance From Waist [m]", + "fields": [ + "electronBeam.epsi_dx", + "electronBeam.epsi_dz" + ] + } + ] + } + } + ] + }, + { + "name": "Magnet Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bendingMagnet.calculateFieldMethod", + "bendingMagnet.r_magnet", + "bendingMagnet.magneticField", + "bendingMagnet.fdistr" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Divergence +X [mrad]", + "fields": [ + "sourceDivergence.hdiv1", + "sourceDivergence.vdiv1" + ] + }, + { + "label": "Horizontal Divergence -X [mrad]", + "fields": [ + "sourceDivergence.hdiv2", + "sourceDivergence.vdiv2" + ] + } + ] + } + } + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "bendingMagnet" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "undulatorBeam.energy", + "undulator.select_energy", + "undulator.energy_harmonic", + "undulator.photon_energy", + "undulator.emin", + "undulator.emax", + "undulator.maxangle" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "undulator.select_energy", + "undulator.energy_harmonic", + "undulator.photon_energy", + "undulator.emin", + "undulator.emax", + "undulator.maxangle", + "undulator.ng_e" + ] + } + } + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "undulatorBeam.energy", + "undulatorBeam.energy_spread", + "undulatorBeam.current", + "undulatorBeam.number_of_bunches" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Twiss Parameters", + "Vertical Twiss Parameters" + ], + "rows": [ + { + "label": "Horizontal Emittance [nm]", + "fields": [ + "undulatorBeam.emittance_x", + "undulatorBeam.emittance_y" + ] + }, + { + "label": "Horizontal Beta [m]", + "description": 1e-99, + "fields": [ + "undulatorBeam.beta_x", + "undulatorBeam.beta_y" + ] + }, + { + "label": "Horizontal Alpha [rad]", + "fields": [ + "undulatorBeam.alpha_x", + "undulatorBeam.alpha_y" + ] + }, + { + "label": "Horizontal Dispersion [m]", + "fields": [ + "undulatorBeam.eta_x", + "undulatorBeam.eta_y" + ] + }, + { + "label": "Horizontal Dispersion Derivative [rad]", + "fields": [ + "undulatorBeam.etap_x", + "undulatorBeam.etap_y" + ] + } + ] + } + } + ] + }, + { + "name": "Undulator Properties", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "undulator.period", + "undulator.length" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Deflecting Parameter (K)", + "fields": [ + "undulator.k_horizontal", + "undulator.k_vertical" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "undulator.ng_t", + "undulator.ng_p", + "undulator.ng_j", + "undulator.flag_size", + "undulator.f_coher" + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "undulator" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "wiggler.ph1", + "wiggler.ph2", + "electronBeam.bener" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "wiggler.ph1", + "wiggler.ph2" + ] + } + } + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "electronBeam.bener" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Z" + ], + "rows": [ + { + "label": "X Sigma [µm]", + "fields": [ + "electronBeam.sigmax", + "electronBeam.sigmaz" + ] + }, + { + "label": "X Emittance [nrad]", + "fields": [ + "electronBeam.epsi_x", + "electronBeam.epsi_z" + ] + }, + { + "label": "X Distance From Waist [m]", + "fields": [ + "electronBeam.epsi_dx", + "electronBeam.epsi_dz" + ] + } + ] + } + } + ] + }, + { + "name": "Wiggler Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "wiggler.b_from", + "wiggler.kValue", + "wiggler.trajFile", + "wiggler.nPer", + "wiggler.per", + "wiggler.shift_x_flag", + "wiggler.shift_x_value", + "wiggler.shift_betax_flag", + "wiggler.shift_betax_value" + ] + } + } + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "wiggler" + }, + { + "layout": "panel", + "config": { + "title": "Histogram", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "histogramReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "histogramReport.*" + ], + "reportLayout": { + "layout": "graph2d" + } + } + } + ], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "histogramReport.distanceFromSource", + "histogramReport.column", + "histogramReport.weight", + "histogramReport.histogramBins", + "histogramReport.notes" + ] + } + } + ] + }, + "_NAME": "histogramReport" + }, + { + "layout": "panel", + "config": { + "title": "PlotXY", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "plotXYReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "plotXYReport.*" + ], + "reportLayout": { + "layout": "heatplot" + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "plotXYReport.x", + "plotXYReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "plotXYReport.weight", + "plotXYReport.histogramBins", + "plotXYReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "plotXYReport.horizontalSize", + "plotXYReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "plotXYReport.horizontalOffset", + "plotXYReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "plotXYReport.aspectRatio", + "plotXYReport.colorMap", + "plotXYReport.notes", + "plotXYReport.distanceFromSource" + ] + } + } + ] + }, + "_NAME": "plotXYReport" + } + ] + }, + { + "name": "Beamline", + "items": [ + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "initialIntensityReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "initialIntensityReport.*" + ], + "reportLayout": { + "layout": "heatplot" + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "initialIntensityReport.x", + "initialIntensityReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "initialIntensityReport.weight", + "initialIntensityReport.histogramBins", + "initialIntensityReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "initialIntensityReport.horizontalSize", + "initialIntensityReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "initialIntensityReport.horizontalOffset", + "initialIntensityReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "initialIntensityReport.aspectRatio", + "initialIntensityReport.colorMap", + "initialIntensityReport.notes" + ] + } + } + ] + }, + "_NAME": "initialIntensityReport" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "watchpointReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "watchpointReport.*" + ], + "reportLayout": { + "layout": "heatplot" + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "watchpointReport.x", + "watchpointReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "watchpointReport.weight", + "watchpointReport.histogramBins", + "watchpointReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "watchpointReport.horizontalSize", + "watchpointReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "watchpointReport.horizontalOffset", + "watchpointReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "watchpointReport.aspectRatio", + "watchpointReport.colorMap", + "watchpointReport.notes" + ] + } + } + ] + }, + "_NAME": "watchpointReport" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "beamStatisticsReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "beamStatisticsReport.*" + ], + "reportLayout": { + "layout": "graph2d" + } + } + } + ], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "beamStatisticsReport.y1", + "beamStatisticsReport.y2", + "beamStatisticsReport.y3", + "beamStatisticsReport.epsilon", + "beamStatisticsReport.driftDivisions", + "beamStatisticsReport.includeApertures", + "beamStatisticsReport.k_apert_x", + "beamStatisticsReport.k_apert_y", + "beamStatisticsReport.notes" + ] + } + } + ] + }, + "_NAME": "beamStatisticsReport" + } + ] + } + ] + }, + { + "layout": "panel", + "config": { + "basic": [], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "aperture.title", + "aperture.position", + "aperture.shape" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "aperture.horizontalSize", + "aperture.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "aperture.horizontalOffset", + "aperture.verticalOffset" + ] + } + ] + } + } + ] + }, + "_NAME": "aperture" + }, + { + "layout": "panel", + "config": { + "basic": [], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crl.title", + "crl.position", + "crl.numberOfLenses", + "crl.numberOfEmptySlots", + "crl.pilingThickness", + "crl.focalDistance", + "crl.fhit_c", + "crl.lensDiameter", + "crl.fmirr", + "crl.rmirr", + "crl.lensThickness", + "crl.useCCC", + "crl.initialCurvature", + "crl.fcyl", + "crl.cil_ang", + "crl.refractionIndex", + "crl.attenuationCoefficient" + ] + } + } + ] + }, + "_NAME": "crl" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Misalignment", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Y", + "Z" + ], + "rows": [ + { + "label": "X Offset [mm]", + "fields": [ + "crystal.offx", + "crystal.offy", + "crystal.offz" + ] + }, + { + "label": "X Rotation [CCW, deg]", + "fields": [ + "crystal.x_rot", + "crystal.y_rot", + "crystal.z_rot" + ] + } + ] + } + } + ] + }, + { + "name": "Main Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.title", + "crystal.position", + "crystal.fmirr", + "crystal.f_central", + "crystal.t_incidence", + "crystal.t_reflection", + "crystal.f_phot_cent", + "crystal.phot_cent", + "crystal.r_lambda", + "crystal.alpha" + ] + } + } + ] + }, + { + "name": "Surface Shape", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.f_ext", + "crystal.f_default", + "crystal.ssour", + "crystal.simag", + "crystal.theta", + "crystal.f_side", + "crystal.rmirr", + "crystal.param", + "crystal.axmaj", + "crystal.axmin", + "crystal.ell_the", + "crystal.f_convex", + "crystal.fcyl", + "crystal.cil_ang", + "crystal.r_maj", + "crystal.r_min", + "crystal.f_torus" + ] + } + } + ] + }, + { + "name": "Crystal", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.f_refrac", + "crystal.f_mosaic", + "crystal.f_bragg_a", + "crystal.a_bragg", + "crystal.order", + "crystal.spread_mos", + "crystal.thickness", + "crystal.mosaic_seed", + "crystal.f_johansson", + "crystal.r_johansson" + ] + } + } + ] + }, + { + "name": "Bragg", + "items": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Material of the crystal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "braggMaterial" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Miller's indices" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "braggMillerH", + "braggMillerK", + "braggMillerL" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.braggTemperaturFactor", + "crystal.braggMinEnergy", + "crystal.braggMaxEnergy", + "crystal.braggEnergyStep" + ] + } + } + ] + }, + { + "name": "Dimensions", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.fhit_c", + "crystal.fshape", + "crystal.halfWidthX1", + "crystal.halfWidthX2", + "crystal.halfLengthY1", + "crystal.halfLengthY2", + "crystal.externalOutlineMajorAxis", + "crystal.externalOutlineMinorAxis", + "crystal.internalOutlineMajorAxis", + "crystal.internalOutlineMinorAxis" + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "crystal" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "emptyElement.title", + "emptyElement.position", + "emptyElement.alpha" + ] + } + } + ] + }, + "_NAME": "emptyElement" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Misalignment", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Y", + "Z" + ], + "rows": [ + { + "label": "X Offset [mm]", + "fields": [ + "grating.offx", + "grating.offy", + "grating.offz" + ] + }, + { + "label": "X Rotation [CCW, deg]", + "fields": [ + "grating.x_rot", + "grating.y_rot", + "grating.z_rot" + ] + } + ] + } + } + ] + }, + { + "name": "Main Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.title", + "grating.position", + "grating.fmirr", + "grating.f_central", + "grating.f_phot_cent", + "grating.phot_cent", + "grating.r_lambda", + "grating.t_incidence", + "grating.t_reflection", + "grating.alpha" + ] + } + } + ] + }, + { + "name": "Surface Shape", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.f_ext", + "grating.f_default", + "grating.ssour", + "grating.simag", + "grating.theta", + "grating.f_side", + "grating.rmirr", + "grating.param", + "grating.axmaj", + "grating.axmin", + "grating.ell_the", + "grating.f_convex", + "grating.fcyl", + "grating.cil_ang", + "grating.r_maj", + "grating.r_min", + "grating.f_torus" + ] + } + } + ] + }, + { + "name": "Grating", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.f_ruling", + "grating.rulingDensity", + "grating.rulingDensityCenter", + "grating.rulingDensityPolynomial" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Entrance", + "Exit" + ], + "rows": [ + { + "label": "Entrance Slit Distance [mm]", + "fields": [ + "grating.holo_r1", + "grating.holo_r2" + ] + }, + { + "label": "Entrance Slit Incidence Angle [deg]", + "fields": [ + "grating.holo_del", + "grating.holo_gam" + ] + }, + { + "label": "Entrance Slit Rotation Angle [deg]", + "fields": [ + "grating.holo_rt1", + "grating.holo_rt2" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.f_pw", + "grating.f_pw_c", + "grating.f_virtual", + "grating.holo_w", + "grating.azim_fan", + "grating.dist_fan", + "grating.coma_fac", + "grating.rul_a1", + "grating.rul_a2", + "grating.rul_a3", + "grating.rul_a4", + "grating.f_rul_abs" + ] + } + } + ] + }, + { + "name": "Diffraction", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.order", + "grating.f_mono", + "grating.f_hunt", + "grating.hunt_h", + "grating.hunt_l", + "grating.blaze" + ] + } + } + ] + }, + { + "name": "Dimensions", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.fhit_c", + "grating.fshape", + "grating.halfWidthX1", + "grating.halfWidthX2", + "grating.halfLengthY1", + "grating.halfLengthY2", + "grating.externalOutlineMajorAxis", + "grating.externalOutlineMinorAxis", + "grating.internalOutlineMajorAxis", + "grating.internalOutlineMinorAxis" + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "grating" + }, + { + "layout": "panel", + "config": { + "basic": [], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "lens.title", + "lens.position", + "lens.focal_x", + "lens.focal_z" + ] + } + } + ] + }, + "_NAME": "lens" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Misalignment", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Y", + "Z" + ], + "rows": [ + { + "label": "X Offset [mm]", + "fields": [ + "mirror.offx", + "mirror.offy", + "mirror.offz" + ] + }, + { + "label": "X Rotation [CCW, deg]", + "fields": [ + "mirror.x_rot", + "mirror.y_rot", + "mirror.z_rot" + ] + } + ] + } + } + ] + }, + { + "name": "Main Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.title", + "mirror.position", + "mirror.fmirr", + "mirror.t_incidence", + "mirror.alpha" + ] + } + } + ] + }, + { + "name": "Surface Shape", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.f_ext", + "mirror.f_default", + "mirror.ssour", + "mirror.simag", + "mirror.theta", + "mirror.f_side", + "mirror.rmirr", + "mirror.param", + "mirror.axmaj", + "mirror.axmin", + "mirror.ell_the", + "mirror.f_convex", + "mirror.fcyl", + "mirror.cil_ang", + "mirror.r_maj", + "mirror.r_min", + "mirror.f_torus" + ] + } + } + ] + }, + { + "name": "Reflectivity", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.f_reflec", + "mirror.f_refl", + "mirror.reflectivityMinEnergy", + "mirror.reflectivityMaxEnergy", + "mirror.prereflStep", + "mirror.prereflElement", + "mirror.prereflDensity", + "mirror.f_thick" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Material", + "Density [g/m³]" + ], + "rows": [ + { + "label": "Material Substrate", + "fields": [ + "mirror.mlayerSubstrateMaterial", + "mirror.mlayerSubstrateDensity" + ] + }, + { + "label": "Material Even Sublayer", + "fields": [ + "mirror.mlayerEvenSublayerMaterial", + "mirror.mlayerEvenSublayerDensity" + ] + }, + { + "label": "Material Odd Sublayer", + "fields": [ + "mirror.mlayerOddSublayerMaterial", + "mirror.mlayerOddSublayerDensity" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.mlayerBilayerNumber", + "mirror.mlayerBilayerThickness", + "mirror.mlayerGammaRatio", + "mirror.mlayerEvenRoughness", + "mirror.mlayerOddRoughness" + ] + } + } + ] + }, + { + "name": "Dimensions", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.fhit_c", + "mirror.fshape", + "mirror.halfWidthX1", + "mirror.halfWidthX2", + "mirror.halfLengthY1", + "mirror.halfLengthY2", + "mirror.externalOutlineMajorAxis", + "mirror.externalOutlineMinorAxis", + "mirror.internalOutlineMajorAxis", + "mirror.internalOutlineMinorAxis" + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "mirror" + }, + { + "layout": "panel", + "config": { + "basic": [], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "obstacle.title", + "obstacle.position", + "obstacle.shape" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "obstacle.horizontalSize", + "obstacle.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "obstacle.horizontalOffset", + "obstacle.verticalOffset" + ] + } + ] + } + } + ] + }, + "_NAME": "obstacle" + }, + + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.name" + ] + } + } + ] + }, + "_NAME": "simulation" + }, + + { + "layout": "panel", + "config": { + "basic": [], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "watch.title", + "watch.position" + ] + } + } + ] + }, + "_NAME": "watch" + }, + + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "zonePlate.title", + "zonePlate.position", + "zonePlate.zone_plate_type", + "zonePlate.width_coating", + "zonePlate.height", + "zonePlate.diameter", + "zonePlate.b_min", + "zonePlate.zone_plate_material", + "zonePlate.template_material", + "zonePlate.n_points", + "zonePlate.last_index" + ] + } + } + ] + }, + "_NAME": "zonePlate" + } + ] +} From 417c2f85f1c0184d5ccd42988dc23c8aa457adf6 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 7 Mar 2023 21:49:47 +0000 Subject: [PATCH 05/68] prepare interpolation for custom types --- react/src/hook/shown.ts | 5 +-- react/src/hook/string.ts | 47 -------------------- react/src/layout/form.tsx | 2 +- react/src/layout/input/file.tsx | 4 +- react/src/layout/multipanel.tsx | 4 +- react/src/layout/navbar.tsx | 8 ++-- react/src/layout/panel.tsx | 4 +- react/src/layout/tabs.tsx | 2 +- react/src/layout/text.tsx | 4 +- react/src/utility/string.ts | 77 +++++++++++++++++++++++++++++++++ 10 files changed, 93 insertions(+), 64 deletions(-) delete mode 100644 react/src/hook/string.ts diff --git a/react/src/hook/shown.ts b/react/src/hook/shown.ts index 4097733bb1..61c6f2c969 100644 --- a/react/src/hook/shown.ts +++ b/react/src/hook/shown.ts @@ -1,10 +1,9 @@ import { AbstractModelsWrapper } from "../data/wrapper"; -import { useEvaluatedInterpString, ValueSelector } from "./string" +import { evaluateInterpStringDependencies, ValueSelector } from "../utility/string" export function useShown(shownStr: string, defaultValue: boolean, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { - let evalInterpStrFn = useEvaluatedInterpString; if(shownStr) { - let shown = evalInterpStrFn(modelsWrapper, shownStr, valueSelector); + let shown = evaluateInterpStringDependencies(shownStr, modelsWrapper, valueSelector); if(typeof(shown) !== 'boolean'){ throw new Error(`'shown' function did not evaluate to a boolean "${shownStr}" -> ${shown}`) } diff --git a/react/src/hook/string.ts b/react/src/hook/string.ts deleted file mode 100644 index 00e5708e4d..0000000000 --- a/react/src/hook/string.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { ModelsAccessor } from "../data/accessor"; -import { Dependency } from "../data/dependency"; -import { AbstractModelsWrapper } from "../data/wrapper"; -import { FormFieldState } from "../store/formState"; - -export type ValueSelector = (v: T) => any; - -export const ValueSelectors = { - Models: (v: any) => v, - Fields: (v: FormFieldState) => v.value -} - -export function useInterpolatedString(modelsWrapper: AbstractModelsWrapper, str: string, valueSelector: ValueSelector) { - // need to convert values to strings - return interpolateString(modelsWrapper, str, v => `${v}`, valueSelector); -} - -function interpolateString(modelsWrapper: AbstractModelsWrapper, str: string, conversionFn: (v: F) => any, valueSelector: ValueSelector) { - let matches = [...str.matchAll(/\$\(([^\%]+?)\)/g)]; - let mappingsArr = matches.map(([originalString, mappedGroup]) => { - return { - original: originalString, - dependency: new Dependency(mappedGroup) - } - }); - - let modelAccessor = new ModelsAccessor(modelsWrapper, mappingsArr.map(v => v.dependency)); - - let interpolatedStr = str; - - mappingsArr.map(mapping => { - return { - ...mapping, - value: (valueSelector)(modelAccessor.getFieldValue(mapping.dependency)) - } - }).forEach(({ original, value }) => { - interpolatedStr = interpolatedStr.replace(original, `${conversionFn(value)}`); - }) - - return interpolatedStr; -} - -export function useEvaluatedInterpString(modelsWrapper: AbstractModelsWrapper, str: string, valueSelector: ValueSelector) { - // need to JSON stringify values, strings must be quoted and arrays must be recursively stringified - let interpStr = interpolateString(modelsWrapper, str, v => JSON.stringify(v), valueSelector); - return eval(interpStr); -} diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index 073d8d3d38..9b9111441f 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -13,7 +13,7 @@ import { useShown } from "../hook/shown"; import { CModelsWrapper, CFormStateWrapper } from "../data/wrapper"; import { useStore } from "react-redux"; import { CSchema } from "../data/appwrapper"; -import { ValueSelectors } from "../hook/string"; +import { ValueSelectors } from "../utility/string"; export function LayoutWithFormController(Child: LayoutType): LayoutType { return class extends Child { diff --git a/react/src/layout/input/file.tsx b/react/src/layout/input/file.tsx index 153504ca94..26148288a8 100644 --- a/react/src/layout/input/file.tsx +++ b/react/src/layout/input/file.tsx @@ -5,7 +5,7 @@ import { FunctionComponent, useContext, useState } from "react"; import { Button, Form, Modal } from "react-bootstrap"; import { CAppName, CSimulationInfoPromise } from "../../data/appwrapper"; import { CModelsWrapper } from "../../data/wrapper"; -import { useInterpolatedString, ValueSelectors } from "../../hook/string"; +import { interpolateStringDependencies, ValueSelectors } from "../../utility/string"; import { downloadAs } from "../../utility/download"; import { SchemaLayout } from "../../utility/schema"; import { LayoutProps } from "../layout"; @@ -44,7 +44,7 @@ export class FileInputLayout extends InputLayout }), - title: useInterpolatedString(modelsWrapper, this.config.inspectModal.title, ValueSelectors.Models) + title: interpolateStringDependencies(this.config.inspectModal.title, modelsWrapper, ValueSelectors.Models) } : undefined; let [fileNameList, updateFileNameList] = useState(undefined); diff --git a/react/src/layout/multipanel.tsx b/react/src/layout/multipanel.tsx index 9265416c2e..b647396798 100644 --- a/react/src/layout/multipanel.tsx +++ b/react/src/layout/multipanel.tsx @@ -7,7 +7,7 @@ import { Panel } from "../component/reusable/panel"; import { ReportAnimationController, useAnimationReader } from "./report" import { SchemaLayout } from "../utility/schema"; import { useContext } from "react"; -import { useInterpolatedString, ValueSelectors } from "../hook/string"; +import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; import { useWindowSize } from "../hook/breakpoint"; export type MultiPanelConfig = { @@ -33,7 +33,7 @@ export class MultiPanelLayout extends Layout { component = (props: LayoutProps<{}>) => { let { reportName, reportGroupName, frameIdFields } = this.config; let modelsWrapper = useContext(CModelsWrapper); - let title = useInterpolatedString(modelsWrapper, this.config.title, ValueSelectors.Models); + let title = interpolateStringDependencies(this.config.title, modelsWrapper, ValueSelectors.Models); // allow subplots to respond to window resize useWindowSize(); let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index 392d579e83..eac4330c2f 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -1,7 +1,7 @@ import { Nav , Modal, Col, Row } from "react-bootstrap"; import { Navigate, useRoutes, Link, useResolvedPath, useParams } from "react-router-dom"; import { NavbarLeftContainerId, NavbarRightContainerId } from "../component/reusable/navbar"; -import { useInterpolatedString, ValueSelectors } from "../hook/string"; +import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; import { useContext, useState } from "react"; import { LayoutProps, Layout } from "./layout"; import { useStore } from "react-redux"; @@ -46,8 +46,8 @@ export class NavBarModalButton extends Layout { let simulationInfoPromise = useContext(CSimulationInfoPromise); let modelsWrapper = useContext(CModelsWrapper); - let title = useInterpolatedString(modelsWrapper, this.config.title, ValueSelectors.Models); - let modalTitle = useInterpolatedString(modelsWrapper, this.config.modal.title, ValueSelectors.Models); + let title = interpolateStringDependencies(this.config.title, modelsWrapper, ValueSelectors.Models); + let modalTitle = interpolateStringDependencies(this.config.modal.title, modelsWrapper, ValueSelectors.Models); let [modalShown, updateModalShown] = useState(false); @@ -174,7 +174,7 @@ export class NavTabsLayout extends Layout { return ( - {useInterpolatedString(modelsWrapper, tab.title, ValueSelectors.Models)} + {interpolateStringDependencies(tab.title, modelsWrapper, ValueSelectors.Models)} ) diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 00b10d83a3..c36ccd059b 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -1,5 +1,5 @@ import { useContext } from "react"; -import { useInterpolatedString, ValueSelectors } from "../hook/string"; +import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; import { LayoutProps, Layout } from "./layout"; import { useStore } from "react-redux"; import { EditorPanel } from "../component/reusable/panel"; @@ -40,7 +40,7 @@ export class PanelLayout extends Layout { let store = useStore(); - let title = useInterpolatedString(modelsWrapper, this.config.title, ValueSelectors.Models); + let title = interpolateStringDependencies(this.config.title, modelsWrapper, ValueSelectors.Models); let mapLayoutsToComponents = (views: Layout[]) => views.map((child, idx) => { let LayoutComponent = child.component; diff --git a/react/src/layout/tabs.tsx b/react/src/layout/tabs.tsx index b867aa46f5..ee4d942555 100644 --- a/react/src/layout/tabs.tsx +++ b/react/src/layout/tabs.tsx @@ -4,7 +4,7 @@ import { Tab, Tabs } from "react-bootstrap"; import { useShown } from "../hook/shown"; import React from "react"; import { CModelsWrapper } from "../data/wrapper"; -import { ValueSelectors } from "../hook/string"; +import { ValueSelectors } from "../utility/string"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; diff --git a/react/src/layout/text.tsx b/react/src/layout/text.tsx index dd7c8c91c1..496262956e 100644 --- a/react/src/layout/text.tsx +++ b/react/src/layout/text.tsx @@ -2,7 +2,7 @@ import React from "react"; import { FunctionComponent, useContext } from "react"; import { Dependency } from "../data/dependency"; import { CModelsWrapper } from "../data/wrapper"; -import { useInterpolatedString, ValueSelectors } from "../hook/string"; +import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; import { Layout } from "./layout"; export type TextAlign = "left" | "right" | "center" @@ -22,7 +22,7 @@ export class TextLayout extends Layout { component: FunctionComponent<{ [key: string]: any; }> = (props) => { let modelsWrapper = useContext(CModelsWrapper); - let interpText = useInterpolatedString(modelsWrapper, this.config.text, ValueSelectors.Models); + let interpText = interpolateStringDependencies(this.config.text, modelsWrapper, ValueSelectors.Models); let getTextElement = (type: TextType) => { switch(type) { case "header": diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index acb0ef0443..99a1978efc 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -1,3 +1,80 @@ +import { ModelsAccessor } from "../data/accessor"; +import { Dependency } from "../data/dependency"; +import { AbstractModelsWrapper } from "../data/wrapper"; +import { FormFieldState } from "../store/formState"; + +export type ValueSelector = (v: T) => any; + +export const ValueSelectors = { + Models: (v: any) => v, + Fields: (v: FormFieldState) => v.value +} + +export function interpolateStringDependencies(str: string, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { + // need to convert values to strings + return _interpolateStringDependencies(str, modelsWrapper, valueSelector, v => `${v}`); +} + +function getStringReplacementPatterns(str: string): RegExpMatchArray[] { + return [...str.matchAll(/\$\(([^\%]+?)\)/g)]; +} + +function _interpolateString(str: string, mappingFunction: (v: string) => F, valueSerializer: (v: F) => string): string { + let matches = getStringReplacementPatterns(str); + let mappingsArr = matches.map(([originalString, mappedGroup]) => { + return { + original: originalString, + value: mappingFunction(mappedGroup) + } + }); + + let interpolatedStr = str; + + mappingsArr.forEach(({ original, value }) => { + interpolatedStr = interpolatedStr.replace(original, `${valueSerializer(value)}`); + }) + + return interpolatedStr; +} + +function _interpolateStringDependencies(str: string, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector, valueSerializer: (v: F) => string) { + let matches = getStringReplacementPatterns(str); + + let mappingsArr = matches.map(([originalString, mappedGroup]) => { + return { + original: originalString, + dependency: new Dependency(mappedGroup) + } + }); + + let modelAccessor = new ModelsAccessor(modelsWrapper, mappingsArr.map(v => v.dependency)); + + let interpolatedStr = str; + + mappingsArr.map(mapping => { + return { + ...mapping, + value: (valueSelector)(modelAccessor.getFieldValue(mapping.dependency)) + } + }).forEach(({ original, value }) => { + interpolatedStr = interpolatedStr.replace(original, `${valueSerializer(value)}`); + }) + + return interpolatedStr; +} + +export function evaluateInterpStringDependencies (str: string, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { + // need to JSON stringify values, strings must be quoted and arrays must be recursively stringified + let interpStr = _interpolateStringDependencies(str, modelsWrapper, valueSelector, v => JSON.stringify(v)); + return eval(interpStr); +} + +export function evaluateInterpString (str: string, values: {[key: string]: any}) { + let valueSelector = (v: string) => values[v]; + // need to JSON stringify values, strings must be quoted and arrays must be recursively stringified + let interpStr = _interpolateString(str, valueSelector, v => JSON.stringify(v)); + return eval(interpStr); +} export function titleCaseString(str: string): string { return str.split(" ").map(word => { From 760a3912eb3f74424f9fdc5e52dba43dc2551b27 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 7 Mar 2023 22:09:47 +0000 Subject: [PATCH 06/68] use better pattern for interpolation --- react/src/hook/shown.ts | 4 +- react/src/layout/input/file.tsx | 4 +- react/src/layout/multipanel.tsx | 4 +- react/src/layout/navbar.tsx | 8 +-- react/src/layout/panel.tsx | 5 +- react/src/layout/text.tsx | 4 +- react/src/utility/string.ts | 120 ++++++++++++++++++-------------- 7 files changed, 81 insertions(+), 68 deletions(-) diff --git a/react/src/hook/shown.ts b/react/src/hook/shown.ts index 61c6f2c969..30a78bc844 100644 --- a/react/src/hook/shown.ts +++ b/react/src/hook/shown.ts @@ -1,9 +1,9 @@ import { AbstractModelsWrapper } from "../data/wrapper"; -import { evaluateInterpStringDependencies, ValueSelector } from "../utility/string" +import { interpolate, ValueSelector } from "../utility/string" export function useShown(shownStr: string, defaultValue: boolean, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { if(shownStr) { - let shown = evaluateInterpStringDependencies(shownStr, modelsWrapper, valueSelector); + let shown = interpolate(shownStr).withDependencies(modelsWrapper, valueSelector).evaluated(); if(typeof(shown) !== 'boolean'){ throw new Error(`'shown' function did not evaluate to a boolean "${shownStr}" -> ${shown}`) } diff --git a/react/src/layout/input/file.tsx b/react/src/layout/input/file.tsx index 26148288a8..9217d5c34d 100644 --- a/react/src/layout/input/file.tsx +++ b/react/src/layout/input/file.tsx @@ -5,7 +5,7 @@ import { FunctionComponent, useContext, useState } from "react"; import { Button, Form, Modal } from "react-bootstrap"; import { CAppName, CSimulationInfoPromise } from "../../data/appwrapper"; import { CModelsWrapper } from "../../data/wrapper"; -import { interpolateStringDependencies, ValueSelectors } from "../../utility/string"; +import { interpolate, ValueSelectors } from "../../utility/string"; import { downloadAs } from "../../utility/download"; import { SchemaLayout } from "../../utility/schema"; import { LayoutProps } from "../layout"; @@ -44,7 +44,7 @@ export class FileInputLayout extends InputLayout }), - title: interpolateStringDependencies(this.config.inspectModal.title, modelsWrapper, ValueSelectors.Models) + title: interpolate(this.config.inspectModal.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw() } : undefined; let [fileNameList, updateFileNameList] = useState(undefined); diff --git a/react/src/layout/multipanel.tsx b/react/src/layout/multipanel.tsx index b647396798..48c007c23e 100644 --- a/react/src/layout/multipanel.tsx +++ b/react/src/layout/multipanel.tsx @@ -7,7 +7,7 @@ import { Panel } from "../component/reusable/panel"; import { ReportAnimationController, useAnimationReader } from "./report" import { SchemaLayout } from "../utility/schema"; import { useContext } from "react"; -import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; +import { interpolate, ValueSelectors } from "../utility/string"; import { useWindowSize } from "../hook/breakpoint"; export type MultiPanelConfig = { @@ -33,7 +33,7 @@ export class MultiPanelLayout extends Layout { component = (props: LayoutProps<{}>) => { let { reportName, reportGroupName, frameIdFields } = this.config; let modelsWrapper = useContext(CModelsWrapper); - let title = interpolateStringDependencies(this.config.title, modelsWrapper, ValueSelectors.Models); + let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); // allow subplots to respond to window resize useWindowSize(); let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index eac4330c2f..2aa991baf9 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -1,7 +1,7 @@ import { Nav , Modal, Col, Row } from "react-bootstrap"; import { Navigate, useRoutes, Link, useResolvedPath, useParams } from "react-router-dom"; import { NavbarLeftContainerId, NavbarRightContainerId } from "../component/reusable/navbar"; -import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; +import { interpolate, ValueSelectors } from "../utility/string"; import { useContext, useState } from "react"; import { LayoutProps, Layout } from "./layout"; import { useStore } from "react-redux"; @@ -46,8 +46,8 @@ export class NavBarModalButton extends Layout { let simulationInfoPromise = useContext(CSimulationInfoPromise); let modelsWrapper = useContext(CModelsWrapper); - let title = interpolateStringDependencies(this.config.title, modelsWrapper, ValueSelectors.Models); - let modalTitle = interpolateStringDependencies(this.config.modal.title, modelsWrapper, ValueSelectors.Models); + let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); + let modalTitle = interpolate(this.config.modal.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); let [modalShown, updateModalShown] = useState(false); @@ -174,7 +174,7 @@ export class NavTabsLayout extends Layout { return ( - {interpolateStringDependencies(tab.title, modelsWrapper, ValueSelectors.Models)} + {interpolate(tab.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw()} ) diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index c36ccd059b..1639b769fe 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -1,10 +1,9 @@ import { useContext } from "react"; -import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; +import { interpolate, ValueSelectors } from "../utility/string"; import { LayoutProps, Layout } from "./layout"; import { useStore } from "react-redux"; import { EditorPanel } from "../component/reusable/panel"; import "./panel.scss"; -import { Col } from "react-bootstrap"; import React from "react"; import { CFormController } from "../data/formController"; import { CModelsWrapper } from "../data/wrapper"; @@ -40,7 +39,7 @@ export class PanelLayout extends Layout { let store = useStore(); - let title = interpolateStringDependencies(this.config.title, modelsWrapper, ValueSelectors.Models); + let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); let mapLayoutsToComponents = (views: Layout[]) => views.map((child, idx) => { let LayoutComponent = child.component; diff --git a/react/src/layout/text.tsx b/react/src/layout/text.tsx index 496262956e..c46681c5fc 100644 --- a/react/src/layout/text.tsx +++ b/react/src/layout/text.tsx @@ -2,7 +2,7 @@ import React from "react"; import { FunctionComponent, useContext } from "react"; import { Dependency } from "../data/dependency"; import { CModelsWrapper } from "../data/wrapper"; -import { interpolateStringDependencies, ValueSelectors } from "../utility/string"; +import { interpolate, ValueSelectors } from "../utility/string"; import { Layout } from "./layout"; export type TextAlign = "left" | "right" | "center" @@ -22,7 +22,7 @@ export class TextLayout extends Layout { component: FunctionComponent<{ [key: string]: any; }> = (props) => { let modelsWrapper = useContext(CModelsWrapper); - let interpText = interpolateStringDependencies(this.config.text, modelsWrapper, ValueSelectors.Models); + let interpText = interpolate(this.config.text).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); let getTextElement = (type: TextType) => { switch(type) { case "header": diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 99a1978efc..0e669cfee6 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -10,70 +10,84 @@ export const ValueSelectors = { Fields: (v: FormFieldState) => v.value } -export function interpolateStringDependencies(str: string, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { - // need to convert values to strings - return _interpolateStringDependencies(str, modelsWrapper, valueSelector, v => `${v}`); -} - function getStringReplacementPatterns(str: string): RegExpMatchArray[] { return [...str.matchAll(/\$\(([^\%]+?)\)/g)]; } -function _interpolateString(str: string, mappingFunction: (v: string) => F, valueSerializer: (v: F) => string): string { - let matches = getStringReplacementPatterns(str); - let mappingsArr = matches.map(([originalString, mappedGroup]) => { - return { - original: originalString, - value: mappingFunction(mappedGroup) - } - }); - - let interpolatedStr = str; - - mappingsArr.forEach(({ original, value }) => { - interpolatedStr = interpolatedStr.replace(original, `${valueSerializer(value)}`); - }) - - return interpolatedStr; +export class InterpolationBase { + matches: RegExpMatchArray[]; + constructor(private str: string) { + this.matches = getStringReplacementPatterns(str); + } + + withValues(values: {[key: string]: any}): InterpolationResult { + let mappingsArr = this.matches.map(([originalString, mappedGroup]) => { + return { + original: originalString, + value: values[mappedGroup] + } + }); + + return new InterpolationResult( + (serializer) => { + let interpolatedStr = this.str; + + mappingsArr.forEach(({ original, value }) => { + interpolatedStr = interpolatedStr.replace(original, `${serializer(value)}`); + }) + + return interpolatedStr; + } + ) + } + + withDependencies(modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector): InterpolationResult { + let mappingsArr = this.matches.map(([originalString, mappedGroup]) => { + return { + original: originalString, + dependency: new Dependency(mappedGroup) + } + }); + + let modelAccessor = new ModelsAccessor(modelsWrapper, mappingsArr.map(v => v.dependency)); + + let valuesArr = mappingsArr.map(mapping => { + return { + ...mapping, + value: (valueSelector)(modelAccessor.getFieldValue(mapping.dependency)) + } + }) + + return new InterpolationResult( + (serializer) => { + let interpolatedStr = this.str; + + valuesArr.forEach(({ original, value }) => { + interpolatedStr = interpolatedStr.replace(original, `${serializer(value)}`); + }) + + return interpolatedStr; + } + ) + } } -function _interpolateStringDependencies(str: string, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector, valueSerializer: (v: F) => string) { - let matches = getStringReplacementPatterns(str); +export class InterpolationResult { + constructor(private interpString: (serializer: (v: any) => string) => string) { - let mappingsArr = matches.map(([originalString, mappedGroup]) => { - return { - original: originalString, - dependency: new Dependency(mappedGroup) - } - }); + } - let modelAccessor = new ModelsAccessor(modelsWrapper, mappingsArr.map(v => v.dependency)); - - let interpolatedStr = str; - - mappingsArr.map(mapping => { - return { - ...mapping, - value: (valueSelector)(modelAccessor.getFieldValue(mapping.dependency)) - } - }).forEach(({ original, value }) => { - interpolatedStr = interpolatedStr.replace(original, `${valueSerializer(value)}`); - }) - - return interpolatedStr; -} + raw(): string { + return this.interpString(v => `${v}`); + } -export function evaluateInterpStringDependencies (str: string, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { - // need to JSON stringify values, strings must be quoted and arrays must be recursively stringified - let interpStr = _interpolateStringDependencies(str, modelsWrapper, valueSelector, v => JSON.stringify(v)); - return eval(interpStr); + evaluated(): any { + return eval(this.interpString(v => JSON.stringify(v))); + } } -export function evaluateInterpString (str: string, values: {[key: string]: any}) { - let valueSelector = (v: string) => values[v]; - // need to JSON stringify values, strings must be quoted and arrays must be recursively stringified - let interpStr = _interpolateString(str, valueSelector, v => JSON.stringify(v)); - return eval(interpStr); +export function interpolate(str: string): InterpolationBase { + return new InterpolationBase(str); } export function titleCaseString(str: string): string { From 86d303396ebe19584d7830c57caca4a4f74976ec Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 7 Mar 2023 22:23:12 +0000 Subject: [PATCH 07/68] allow custom validators on generic inputs --- react/src/layout/input/number.tsx | 19 ++++++++++++++++--- react/src/layout/input/string.tsx | 10 ++++++++-- react/src/utility/string.ts | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/react/src/layout/input/number.tsx b/react/src/layout/input/number.tsx index cddf4cc183..e62e4f8e2b 100644 --- a/react/src/layout/input/number.tsx +++ b/react/src/layout/input/number.tsx @@ -1,9 +1,14 @@ import React, { ChangeEventHandler, FunctionComponent } from "react"; import { Form } from "react-bootstrap"; +import { interpolate } from "../../utility/string"; import { LayoutProps } from "../layout"; import { InputComponentProps, InputConfigBase, InputLayout } from "./input"; -export abstract class NumberInputLayout extends InputLayout { +export type NumberConfigBase = { + valid?: string +} & InputConfigBase + +export abstract class NumberInputLayout extends InputLayout { component: FunctionComponent>> = (props) => { let onChange: ChangeEventHandler = (event) => { props.onChange(event.target.value); @@ -24,7 +29,11 @@ export class FloatInputLayout extends NumberInputLayout { return `${value}`; } validate = (value: string) => { - return (!this.config.isRequired) || (this.hasValue(value) && FloatInputLayout.REGEXP.test(value)); + let v = (!this.config.isRequired) || (this.hasValue(value) && FloatInputLayout.REGEXP.test(value)); + if(this.config.valid) { + return v && interpolate(this.config.valid).withValues({ value }).evaluated(); + } + return v; } } @@ -35,6 +44,10 @@ export class IntegerInputLayout extends NumberInputLayout { } fromModelValue: (value: number) => string = (v) => `${v}`; validate = (value: string) => { - return (!this.config.isRequired) || (this.hasValue(value) && IntegerInputLayout.REGEXP.test(value)); + let v = (!this.config.isRequired) || (this.hasValue(value) && IntegerInputLayout.REGEXP.test(value)); + if(this.config.valid) { + return v && interpolate(this.config.valid).withValues({ value }).evaluated(); + } + return v; } } diff --git a/react/src/layout/input/string.tsx b/react/src/layout/input/string.tsx index bafbb7c3c3..51c88db54e 100644 --- a/react/src/layout/input/string.tsx +++ b/react/src/layout/input/string.tsx @@ -1,9 +1,11 @@ import React, { ChangeEventHandler, FunctionComponent } from 'react'; import { Form } from 'react-bootstrap'; +import { interpolate } from '../../utility/string'; import { AlignmentClass, InputComponentProps, InputConfigBase, InputLayout } from './input'; export type StringInputConfig = { - align: AlignmentClass + align: AlignmentClass, + valid?: string } & InputConfigBase export class StringInputLayout extends InputLayout { @@ -15,7 +17,11 @@ export class StringInputLayout extends InputLayout { } validate = (value: string) => { - return (!this.config.isRequired) || (this.hasValue(value) && value.length > 0); + let v = (!this.config.isRequired) || (this.hasValue(value) && value.length > 0); + if (this.config.valid) { + return v && interpolate(this.config.valid).withValues({ value }).evaluated(); + } + return v; } toModelValue: (value: string) => string = (v) => v; diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 0e669cfee6..b8eac06bf0 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -15,7 +15,7 @@ function getStringReplacementPatterns(str: string): RegExpMatchArray[] { } export class InterpolationBase { - matches: RegExpMatchArray[]; + private matches: RegExpMatchArray[]; constructor(private str: string) { this.matches = getStringReplacementPatterns(str); } From cffb38c0ccad5046335cc8d4595bd4796b008f46 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 7 Mar 2023 22:43:16 +0000 Subject: [PATCH 08/68] add array type and beamline type, add custom input types --- react/src/layout/input/array.tsx | 20 ++++++++ react/src/layout/input/inputs.ts | 4 +- react/src/utility/schema.ts | 7 ++- .../static/react-json/shadow-schema.json | 47 ++++++++++++------- 4 files changed, 59 insertions(+), 19 deletions(-) create mode 100644 react/src/layout/input/array.tsx diff --git a/react/src/layout/input/array.tsx b/react/src/layout/input/array.tsx new file mode 100644 index 0000000000..c623df8ae0 --- /dev/null +++ b/react/src/layout/input/array.tsx @@ -0,0 +1,20 @@ +import { InputConfigBase, InputLayout } from "./input"; + +export type ArrayInputConfig = { + models: string[] +} & InputConfigBase + +// TODO: garsuga, implement +export class ArrayInputLayout extends InputLayout { + toModelValue: (value: any[]) => any[] = (value) => { + return value; + } + + fromModelValue: (value: any[]) => any[] = (value) => { + return value; + }; + + validate: (value: any[]) => boolean = (value) => { + return true; + }; +} diff --git a/react/src/layout/input/inputs.ts b/react/src/layout/input/inputs.ts index 568374918a..a255121bb7 100644 --- a/react/src/layout/input/inputs.ts +++ b/react/src/layout/input/inputs.ts @@ -1,3 +1,4 @@ +import { ArrayInputLayout } from "./array"; import { BooleanInputLayout } from "./boolean"; import { ComputeResultEnumInputLayout, EnumInputLayout, SimulationListEnumInputLayout } from "./enum"; import { FileInputLayout } from "./file"; @@ -14,6 +15,7 @@ export const TYPE_BASES: {[baseName: string]: InputLayoutType} = { 'Enum': EnumInputLayout, 'ComputeEnum': ComputeResultEnumInputLayout, 'SimListEnum': SimulationListEnumInputLayout, - // for omega, replace with real implementation eventually + // moellep: for omega, replace with real implementation eventually 'SimArray': StringInputLayout, + 'Array': ArrayInputLayout } diff --git a/react/src/utility/schema.ts b/react/src/utility/schema.ts index 1a3054f3bb..c1f15f65f7 100644 --- a/react/src/utility/schema.ts +++ b/react/src/utility/schema.ts @@ -143,10 +143,13 @@ export function compileSchemaFromJson(schemaObj: SchemaJson): Schema { if(schemaObj.model) { let missingTypeNames = []; - models = mapProperties(schemaObj.model, (_, modelObj) => { - return mapProperties(modelObj, (_, field) => { + models = mapProperties(schemaObj.model, (modelName, modelObj) => { + return mapProperties(modelObj, (fieldName, field) => { let { displayName, type: typeName, defaultValue, description, shown, min, max } = field; let type = types[typeName]; + if(!typeName) { + throw new Error(`type not defined for model=${modelName} field=${fieldName}`) + } if(!type) { missingTypeNames.push(typeName); } diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index 417c0850fc..a82c6f71b1 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -44,22 +44,13 @@ "defaultValue": 0 } }, - "beamline": [ - { - "models": [ - "aperture", - "crl", - "crystal", - "emptyElement", - "grating", - "lens", - "mirror", - "obstacle", - "watch", - "zonePlate" - ] + "beamline": { + "elements": { + "displayName": "Beamline Elements", + "type": "BeamlineElementsArray", + "defaultValue": [] } - ], + }, "beamStatisticsReport": { "epsilon": { "displayName": "Epsilon", @@ -1936,7 +1927,7 @@ }, "trajFile": { "displayName": "Trajectory File", - "type": "InputFile" + "type": "File" }, "shift_x_flag": { "displayName": "Shift Transversal Velocity", @@ -2093,6 +2084,23 @@ ] } }, + "BeamlineElementsArray": { + "base": "Array", + "config": { + "models": [ + "aperture", + "crl", + "crystal", + "emptyElement", + "grating", + "lens", + "mirror", + "obstacle", + "watch", + "zonePlate" + ] + } + }, "BeamShift": { "base": "Enum", "config": { @@ -3192,6 +3200,13 @@ ] } }, + "ReflectivityMaterial": { + "base": "String", + "config": { + "isRequired": true, + "valid": "!( ! /^[A-Za-z0-9().]+$/.test($(value)) || /^[a-z0-9]/.test($(value)) || /[0-9][a-z]/.test($(value)) )" + } + }, "RulingType": { "base": "Enum", "config": { From 5e41b2aa875cce6a4159cccc73dc66a8ac3b3600 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 8 Mar 2023 00:10:44 +0000 Subject: [PATCH 09/68] fix schema and model resolution errors --- react/src/component/app.tsx | 4 +- react/src/component/reusable/form.tsx | 12 +- react/src/data/formController.ts | 26 +- react/src/data/wrapper.ts | 4 + react/src/store/models.ts | 6 +- .../static/react-json/shadow-schema.json | 1963 +++++++++-------- 6 files changed, 1023 insertions(+), 992 deletions(-) diff --git a/react/src/component/app.tsx b/react/src/component/app.tsx index 47013ff489..b1581f6512 100644 --- a/react/src/component/app.tsx +++ b/react/src/component/app.tsx @@ -14,7 +14,7 @@ import { CRouteHelper, RouteHelper } from "../utility/route"; import { getAppCombinedSchema } from "../utility/schema"; export const AppContextWrapper = (props) => { - const formStateStore = configureStore({ + const modelsStore = configureStore({ reducer: { [modelsSlice.name]: modelsSlice.reducer, [formStatesSlice.name]: formStatesSlice.reducer, @@ -27,7 +27,7 @@ export const AppContextWrapper = (props) => { const routeHelper = new RouteHelper(appName, schema); let appWrapper = new AppWrapper(appName, routeHelper); return ( - + diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 63d33e0f97..7de82fd9e1 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -56,7 +56,8 @@ export function FormStateInitializer(props) { formSelectors }) - let modelNames = Object.keys(schema.models); + //let modelNames = Object.keys(schema.models); + let modelNames = models.getModelNames(store.getState()); useEffect(() => { let state = store.getState(); @@ -66,7 +67,14 @@ export function FormStateInitializer(props) { value: models.getModel(mn, state) } }).forEach(({ modelName, value }) => { - formState.updateModel(modelName, formStateFromModel(value, schema.models[modelName])) + if(!value) { + throw new Error(`could not get model=${modelName}`); + } + let modelSchema = schema.models[modelName]; + if(!modelSchema) { + throw new Error(`could not get schema for model=${modelName}`); + } + formState.updateModel(modelName, formStateFromModel(value, modelSchema)); }); updateHasInit(true); diff --git a/react/src/data/formController.ts b/react/src/data/formController.ts index 3e0685931b..4634550145 100644 --- a/react/src/data/formController.ts +++ b/react/src/data/formController.ts @@ -10,14 +10,26 @@ import { InputLayout } from "../layout/input/input"; -export let formStateFromModel = (model: ModelState, modelSchema: SchemaModel) => mapProperties(modelSchema, (fieldName, { type }) => { - return { - valid: type.validate(model[fieldName]), - value: type.fromModelValue(model[fieldName]), - touched: false, - active: true +export let formStateFromModel = (model: ModelState, modelSchema: SchemaModel) => { + if(!modelSchema) { + throw new Error(`while converting model to form state, model schema was undefiend; model=${JSON.stringify(model)}`); + } + if(!model) { + throw new Error(`while converting model to form state, model was undefined; schema=${JSON.stringify(modelSchema)}`); } -}) + return mapProperties(modelSchema, (fieldName, { type }) => { + if(!(fieldName in model)) { + throw new Error(`model=${JSON.stringify(model)} was missing field=${fieldName}`) + } + + return { + valid: type.validate(model[fieldName]), + value: type.fromModelValue(model[fieldName]), + touched: false, + active: true + } + }) +} export const CFormController = React.createContext(undefined); diff --git a/react/src/data/wrapper.ts b/react/src/data/wrapper.ts index c36a865d9d..d36f9083a2 100644 --- a/react/src/data/wrapper.ts +++ b/react/src/data/wrapper.ts @@ -91,6 +91,10 @@ export class ModelsWrapper extends AbstractModelsWrapper { return this.modelSelectors.selectModel(modelName)(state); } + getModelNames = (state: any): string[] => { + return this.modelSelectors.selectModelNames()(state); + } + updateModel = (modelName: string, value: ModelState) => { //console.log("dispatching update to ", modelName, " changing to value ", value); this.dispatch(this.modelActions.updateModel({ diff --git a/react/src/store/models.ts b/react/src/store/models.ts index 498267ca26..3efa3a00fa 100644 --- a/react/src/store/models.ts +++ b/react/src/store/models.ts @@ -31,10 +31,14 @@ export let modelActions: ModelActions = { } export type ModelSelectors = { - selectModel: (name: string) => ((state: any) => ModelState) + selectModel: (name: string) => ((state: any) => ModelState), + selectModelNames: () => ((state: any) => string[]) } export let modelSelectors: ModelSelectors = { selectModel: (name: string) => { return (state: any) => state[modelsSlice.name][name]; + }, + selectModelNames: () => { + return (state: any) => Object.keys(state[modelsSlice.name]); } } diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index a82c6f71b1..ad2b2ebf0c 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -3420,1031 +3420,1034 @@ }, { "layout": "navTabs", - "tabs": [ - { - "name": "Source", - "items": [ - { - "layout": "panel", - "config": { - "title": "Geometric Source", - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "geometricSource.fsour", - "geometricSource.wxsou", - "geometricSource.wzsou", - "geometricSource.sigmax", - "geometricSource.sigmaz" - ] + "config": { + "tabs": [ + { + "name": "Source", + "items": [ + { + "layout": "panel", + "config": { + "title": "Geometric Source", + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "geometricSource.fsour", + "geometricSource.wxsou", + "geometricSource.wzsou", + "geometricSource.sigmax", + "geometricSource.sigmaz" + ] + } } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Geometry Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.npoint", - "simulation.istar1", - "geometricSource.fsour", - "geometricSource.wxsou", - "geometricSource.wzsou", - "geometricSource.sigmax", - "geometricSource.sigmaz", - "geometricSource.fdistr" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Divergence +X [mrad]", - "fields": [ - "sourceDivergence.hdiv1", - "sourceDivergence.vdiv1" - ] - }, - { - "label": "Horizontal Divergence -X [mrad]", - "fields": [ - "sourceDivergence.hdiv2", - "sourceDivergence.vdiv2" - ] - }, - { - "label": "Horizontal Sigma (X) [mrad]", - "fields": [ - "geometricSource.sigdix", - "geometricSource.sigdiz" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "geometricSource.cone_min", - "geometricSource.cone_max", - "geometricSource.fsource_depth", - "geometricSource.wysou", - "geometricSource.sigmay" - ] - } - } - ] - }, - { - "name": "Energy/Polarization Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "geometricSource.f_color", - "geometricSource.singleEnergyValue", - "geometricSource.ph1", - "geometricSource.ph2", - "geometricSource.f_polar", - "geometricSource.f_coher", - "geometricSource.pol_angle", - "geometricSource.pol_deg" - ] + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Geometry Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "geometricSource.fsour", + "geometricSource.wxsou", + "geometricSource.wzsou", + "geometricSource.sigmax", + "geometricSource.sigmaz", + "geometricSource.fdistr" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Divergence +X [mrad]", + "fields": [ + "sourceDivergence.hdiv1", + "sourceDivergence.vdiv1" + ] + }, + { + "label": "Horizontal Divergence -X [mrad]", + "fields": [ + "sourceDivergence.hdiv2", + "sourceDivergence.vdiv2" + ] + }, + { + "label": "Horizontal Sigma (X) [mrad]", + "fields": [ + "geometricSource.sigdix", + "geometricSource.sigdiz" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "geometricSource.cone_min", + "geometricSource.cone_max", + "geometricSource.fsource_depth", + "geometricSource.wysou", + "geometricSource.sigmay" + ] + } } - } - ] - }, - { - "name": "Ray Filter", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "rayFilter.f_bound_sour", - "rayFilter.distance" - ] + ] + }, + { + "name": "Energy/Polarization Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "geometricSource.f_color", + "geometricSource.singleEnergyValue", + "geometricSource.ph1", + "geometricSource.ph2", + "geometricSource.f_polar", + "geometricSource.f_coher", + "geometricSource.pol_angle", + "geometricSource.pol_deg" + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Minimum", - "Maximum" - ], - "rows": [ - { - "label": "X Minimum [mm]", - "fields": [ - "rayFilter.x1", - "rayFilter.x2" - ] - }, - { - "label": "Z Minimum [mm]", - "fields": [ - "rayFilter.z1", - "rayFilter.z2" - ] - } - ] + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } } - } - ] - } - ] + ] + } + ] + } } - } - ] + ] + }, + "_NAME": "geometricSource" }, - "_NAME": "geometricSource" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "bendingMagnet.ph1", - "bendingMagnet.ph2", - "electronBeam.bener" - ] + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "bendingMagnet.ph1", + "bendingMagnet.ph2", + "electronBeam.bener" + ] + } } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Basic Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.npoint", - "simulation.istar1", - "bendingMagnet.ph1", - "bendingMagnet.ph2" - ] - } - } - ] - }, - { - "name": "Beam Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "electronBeam.bener", - "electronBeam.f_pol" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Z" - ], - "rows": [ - { - "label": "X Sigma [µm]", - "fields": [ - "electronBeam.sigmax", - "electronBeam.sigmaz" - ] - }, - { - "label": "X Emittance [nrad]", - "fields": [ - "electronBeam.epsi_x", - "electronBeam.epsi_z" - ] - }, - { - "label": "X Distance From Waist [m]", - "fields": [ - "electronBeam.epsi_dx", - "electronBeam.epsi_dz" - ] - } - ] - } - } - ] - }, - { - "name": "Magnet Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "bendingMagnet.calculateFieldMethod", - "bendingMagnet.r_magnet", - "bendingMagnet.magneticField", - "bendingMagnet.fdistr" - ] + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "bendingMagnet.ph1", + "bendingMagnet.ph2" + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Divergence +X [mrad]", - "fields": [ - "sourceDivergence.hdiv1", - "sourceDivergence.vdiv1" - ] - }, - { - "label": "Horizontal Divergence -X [mrad]", - "fields": [ - "sourceDivergence.hdiv2", - "sourceDivergence.vdiv2" - ] - } - ] + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "electronBeam.bener", + "electronBeam.f_pol" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Z" + ], + "rows": [ + { + "label": "X Sigma [µm]", + "fields": [ + "electronBeam.sigmax", + "electronBeam.sigmaz" + ] + }, + { + "label": "X Emittance [nrad]", + "fields": [ + "electronBeam.epsi_x", + "electronBeam.epsi_z" + ] + }, + { + "label": "X Distance From Waist [m]", + "fields": [ + "electronBeam.epsi_dx", + "electronBeam.epsi_dz" + ] + } + ] + } } - } - ] - }, - { - "name": "Ray Filter", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "rayFilter.f_bound_sour", - "rayFilter.distance" - ] + ] + }, + { + "name": "Magnet Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bendingMagnet.calculateFieldMethod", + "bendingMagnet.r_magnet", + "bendingMagnet.magneticField", + "bendingMagnet.fdistr" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Divergence +X [mrad]", + "fields": [ + "sourceDivergence.hdiv1", + "sourceDivergence.vdiv1" + ] + }, + { + "label": "Horizontal Divergence -X [mrad]", + "fields": [ + "sourceDivergence.hdiv2", + "sourceDivergence.vdiv2" + ] + } + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Minimum", - "Maximum" - ], - "rows": [ - { - "label": "X Minimum [mm]", - "fields": [ - "rayFilter.x1", - "rayFilter.x2" - ] - }, - { - "label": "Z Minimum [mm]", - "fields": [ - "rayFilter.z1", - "rayFilter.z2" - ] - } - ] + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } } - } - ] - } - ] + ] + } + ] + } } - } - ] + ] + }, + "_NAME": "bendingMagnet" }, - "_NAME": "bendingMagnet" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "undulatorBeam.energy", - "undulator.select_energy", - "undulator.energy_harmonic", - "undulator.photon_energy", - "undulator.emin", - "undulator.emax", - "undulator.maxangle" - ] + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "undulatorBeam.energy", + "undulator.select_energy", + "undulator.energy_harmonic", + "undulator.photon_energy", + "undulator.emin", + "undulator.emax", + "undulator.maxangle" + ] + } } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Basic Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.npoint", - "simulation.istar1", - "undulator.select_energy", - "undulator.energy_harmonic", - "undulator.photon_energy", - "undulator.emin", - "undulator.emax", - "undulator.maxangle", - "undulator.ng_e" - ] - } - } - ] - }, - { - "name": "Beam Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "undulatorBeam.energy", - "undulatorBeam.energy_spread", - "undulatorBeam.current", - "undulatorBeam.number_of_bunches" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Twiss Parameters", - "Vertical Twiss Parameters" - ], - "rows": [ - { - "label": "Horizontal Emittance [nm]", - "fields": [ - "undulatorBeam.emittance_x", - "undulatorBeam.emittance_y" - ] - }, - { - "label": "Horizontal Beta [m]", - "description": 1e-99, - "fields": [ - "undulatorBeam.beta_x", - "undulatorBeam.beta_y" - ] - }, - { - "label": "Horizontal Alpha [rad]", - "fields": [ - "undulatorBeam.alpha_x", - "undulatorBeam.alpha_y" - ] - }, - { - "label": "Horizontal Dispersion [m]", - "fields": [ - "undulatorBeam.eta_x", - "undulatorBeam.eta_y" - ] - }, - { - "label": "Horizontal Dispersion Derivative [rad]", - "fields": [ - "undulatorBeam.etap_x", - "undulatorBeam.etap_y" - ] - } - ] - } - } - ] - }, - { - "name": "Undulator Properties", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "undulator.period", - "undulator.length" - ] + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "undulator.select_energy", + "undulator.energy_harmonic", + "undulator.photon_energy", + "undulator.emin", + "undulator.emax", + "undulator.maxangle", + "undulator.ng_e" + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Deflecting Parameter (K)", - "fields": [ - "undulator.k_horizontal", - "undulator.k_vertical" - ] - } - ] + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "undulatorBeam.energy", + "undulatorBeam.energy_spread", + "undulatorBeam.current", + "undulatorBeam.number_of_bunches" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Twiss Parameters", + "Vertical Twiss Parameters" + ], + "rows": [ + { + "label": "Horizontal Emittance [nm]", + "fields": [ + "undulatorBeam.emittance_x", + "undulatorBeam.emittance_y" + ] + }, + { + "label": "Horizontal Beta [m]", + "description": 1e-99, + "fields": [ + "undulatorBeam.beta_x", + "undulatorBeam.beta_y" + ] + }, + { + "label": "Horizontal Alpha [rad]", + "fields": [ + "undulatorBeam.alpha_x", + "undulatorBeam.alpha_y" + ] + }, + { + "label": "Horizontal Dispersion [m]", + "fields": [ + "undulatorBeam.eta_x", + "undulatorBeam.eta_y" + ] + }, + { + "label": "Horizontal Dispersion Derivative [rad]", + "fields": [ + "undulatorBeam.etap_x", + "undulatorBeam.etap_y" + ] + } + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "undulator.ng_t", - "undulator.ng_p", - "undulator.ng_j", - "undulator.flag_size", - "undulator.f_coher" - ] + ] + }, + { + "name": "Undulator Properties", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "undulator.period", + "undulator.length" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Deflecting Parameter (K)", + "fields": [ + "undulator.k_horizontal", + "undulator.k_vertical" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "undulator.ng_t", + "undulator.ng_p", + "undulator.ng_j", + "undulator.flag_size", + "undulator.f_coher" + ] + } } - } - ] - } - ] + ] + } + ] + } } - } - ] + ] + }, + "_NAME": "undulator" }, - "_NAME": "undulator" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "wiggler.ph1", - "wiggler.ph2", - "electronBeam.bener" - ] + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "wiggler.ph1", + "wiggler.ph2", + "electronBeam.bener" + ] + } } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Basic Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.npoint", - "simulation.istar1", - "wiggler.ph1", - "wiggler.ph2" - ] - } - } - ] - }, - { - "name": "Beam Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "electronBeam.bener" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Z" - ], - "rows": [ - { - "label": "X Sigma [µm]", - "fields": [ - "electronBeam.sigmax", - "electronBeam.sigmaz" - ] - }, - { - "label": "X Emittance [nrad]", - "fields": [ - "electronBeam.epsi_x", - "electronBeam.epsi_z" - ] - }, - { - "label": "X Distance From Waist [m]", - "fields": [ - "electronBeam.epsi_dx", - "electronBeam.epsi_dz" - ] - } - ] + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "wiggler.ph1", + "wiggler.ph2" + ] + } } - } - ] - }, - { - "name": "Wiggler Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "wiggler.b_from", - "wiggler.kValue", - "wiggler.trajFile", - "wiggler.nPer", - "wiggler.per", - "wiggler.shift_x_flag", - "wiggler.shift_x_value", - "wiggler.shift_betax_flag", - "wiggler.shift_betax_value" - ] + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "electronBeam.bener" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Z" + ], + "rows": [ + { + "label": "X Sigma [µm]", + "fields": [ + "electronBeam.sigmax", + "electronBeam.sigmaz" + ] + }, + { + "label": "X Emittance [nrad]", + "fields": [ + "electronBeam.epsi_x", + "electronBeam.epsi_z" + ] + }, + { + "label": "X Distance From Waist [m]", + "fields": [ + "electronBeam.epsi_dx", + "electronBeam.epsi_dz" + ] + } + ] + } } - } - ] - }, - { - "name": "Ray Filter", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "rayFilter.f_bound_sour", - "rayFilter.distance" - ] + ] + }, + { + "name": "Wiggler Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "wiggler.b_from", + "wiggler.kValue", + "wiggler.trajFile", + "wiggler.nPer", + "wiggler.per", + "wiggler.shift_x_flag", + "wiggler.shift_x_value", + "wiggler.shift_betax_flag", + "wiggler.shift_betax_value" + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Minimum", - "Maximum" - ], - "rows": [ - { - "label": "X Minimum [mm]", - "fields": [ - "rayFilter.x1", - "rayFilter.x2" - ] - }, - { - "label": "Z Minimum [mm]", - "fields": [ - "rayFilter.z1", - "rayFilter.z2" - ] - } - ] + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } } - } - ] - } - ] - } - } - ] - }, - "_NAME": "wiggler" - }, - { - "layout": "panel", - "config": { - "title": "Histogram", - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "histogramReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "histogramReport.*" - ], - "reportLayout": { - "layout": "graph2d" + ] + } + ] } } - } - ], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "histogramReport.distanceFromSource", - "histogramReport.column", - "histogramReport.weight", - "histogramReport.histogramBins", - "histogramReport.notes" - ] - } - } - ] + ] + }, + "_NAME": "wiggler" }, - "_NAME": "histogramReport" - }, - { - "layout": "panel", - "config": { - "title": "PlotXY", - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "plotXYReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "plotXYReport.*" - ], - "reportLayout": { - "layout": "heatplot" - } - } - } - ], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Value to Plot", - "fields": [ - "plotXYReport.x", - "plotXYReport.y" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "plotXYReport.weight", - "plotXYReport.histogramBins", - "plotXYReport.overrideSize" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "plotXYReport.horizontalSize", - "plotXYReport.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "plotXYReport.horizontalOffset", - "plotXYReport.verticalOffset" - ] + { + "layout": "panel", + "config": { + "title": "Histogram", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "histogramReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "histogramReport.*" + ], + "reportLayout": { + "layout": "graph2d" } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "plotXYReport.aspectRatio", - "plotXYReport.colorMap", - "plotXYReport.notes", - "plotXYReport.distanceFromSource" - ] - } - } - ] - }, - "_NAME": "plotXYReport" - } - ] - }, - { - "name": "Beamline", - "items": [ - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "initialIntensityReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "initialIntensityReport.*" - ], - "reportLayout": { - "layout": "heatplot" } } - } - ], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Value to Plot", - "fields": [ - "initialIntensityReport.x", - "initialIntensityReport.y" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "initialIntensityReport.weight", - "initialIntensityReport.histogramBins", - "initialIntensityReport.overrideSize" - ] + ], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "histogramReport.distanceFromSource", + "histogramReport.column", + "histogramReport.weight", + "histogramReport.histogramBins", + "histogramReport.notes" + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "initialIntensityReport.horizontalSize", - "initialIntensityReport.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "initialIntensityReport.horizontalOffset", - "initialIntensityReport.verticalOffset" - ] + ] + }, + "_NAME": "histogramReport" + }, + { + "layout": "panel", + "config": { + "title": "PlotXY", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "plotXYReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "plotXYReport.*" + ], + "reportLayout": { + "layout": "heatplot" } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "initialIntensityReport.aspectRatio", - "initialIntensityReport.colorMap", - "initialIntensityReport.notes" - ] + } } - } - ] - }, - "_NAME": "initialIntensityReport" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "watchpointReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "watchpointReport.*" - ], - "reportLayout": { - "layout": "heatplot" + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "plotXYReport.x", + "plotXYReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "plotXYReport.weight", + "plotXYReport.histogramBins", + "plotXYReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "plotXYReport.horizontalSize", + "plotXYReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "plotXYReport.horizontalOffset", + "plotXYReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "plotXYReport.aspectRatio", + "plotXYReport.colorMap", + "plotXYReport.notes", + "plotXYReport.distanceFromSource" + ] } } - } - ], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Value to Plot", - "fields": [ - "watchpointReport.x", - "watchpointReport.y" - ] + ] + }, + "_NAME": "plotXYReport" + } + ] + }, + { + "name": "Beamline", + "items": [ + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "initialIntensityReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "initialIntensityReport.*" + ], + "reportLayout": { + "layout": "heatplot" } - ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "watchpointReport.weight", - "watchpointReport.histogramBins", - "watchpointReport.overrideSize" - ] + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "initialIntensityReport.x", + "initialIntensityReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "initialIntensityReport.weight", + "initialIntensityReport.histogramBins", + "initialIntensityReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "initialIntensityReport.horizontalSize", + "initialIntensityReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "initialIntensityReport.horizontalOffset", + "initialIntensityReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "initialIntensityReport.aspectRatio", + "initialIntensityReport.colorMap", + "initialIntensityReport.notes" + ] + } } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "watchpointReport.horizontalSize", - "watchpointReport.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "watchpointReport.horizontalOffset", - "watchpointReport.verticalOffset" - ] + ] + }, + "_NAME": "initialIntensityReport" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "watchpointReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "watchpointReport.*" + ], + "reportLayout": { + "layout": "heatplot" } - ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "watchpointReport.aspectRatio", - "watchpointReport.colorMap", - "watchpointReport.notes" - ] + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "watchpointReport.x", + "watchpointReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "watchpointReport.weight", + "watchpointReport.histogramBins", + "watchpointReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "watchpointReport.horizontalSize", + "watchpointReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "watchpointReport.horizontalOffset", + "watchpointReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "watchpointReport.aspectRatio", + "watchpointReport.colorMap", + "watchpointReport.notes" + ] + } } - } - ] + ] + }, + "_NAME": "watchpointReport" }, - "_NAME": "watchpointReport" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "beamStatisticsReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "beamStatisticsReport.*" - ], - "reportLayout": { - "layout": "graph2d" + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "beamStatisticsReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "beamStatisticsReport.*" + ], + "reportLayout": { + "layout": "graph2d" + } } } - } - ], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "beamStatisticsReport.y1", - "beamStatisticsReport.y2", - "beamStatisticsReport.y3", - "beamStatisticsReport.epsilon", - "beamStatisticsReport.driftDivisions", - "beamStatisticsReport.includeApertures", - "beamStatisticsReport.k_apert_x", - "beamStatisticsReport.k_apert_y", - "beamStatisticsReport.notes" - ] + ], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "beamStatisticsReport.y1", + "beamStatisticsReport.y2", + "beamStatisticsReport.y3", + "beamStatisticsReport.epsilon", + "beamStatisticsReport.driftDivisions", + "beamStatisticsReport.includeApertures", + "beamStatisticsReport.k_apert_x", + "beamStatisticsReport.k_apert_y", + "beamStatisticsReport.notes" + ] + } } - } - ] - }, - "_NAME": "beamStatisticsReport" - } - ] - } - ] + ] + }, + "_NAME": "beamStatisticsReport" + } + ] + } + ] + } + }, { "layout": "panel", From e5243b55e0409985cf1f3cdcd4dfdc1c650ff7c5 Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 17 Mar 2023 00:58:38 +0000 Subject: [PATCH 10/68] wip --- react/src/component/reusable/form.tsx | 3 +- react/src/component/reusable/graph2d.tsx | 6 +- react/src/data/accessor.ts | 3 +- react/src/data/dependency.ts | 16 +- react/src/data/formController.ts | 23 +- react/src/data/wrapper.ts | 75 + react/src/layout/beamline.tsx | 49 +- react/src/layout/form.tsx | 34 +- react/src/layout/input/array.tsx | 9 +- react/src/layout/layouts.ts | 8 +- react/src/layout/report/histogram2d.tsx | 85 + .../shadow/beamlineWatchpointReports.tsx | 21 + react/src/utility/download.ts | 1 + react/src/utility/schema.ts | 4 +- react/src/utility/string.ts | 3 + react/utility/convertschema.ts | 2 + sirepo/feature_config.py | 2 +- .../static/react-json/common-schema.json | 14 + .../static/react-json/shadow-schema.json | 3187 ++++++++--------- .../static/svg/react-svg/aperture.svg | 62 + .../package_data/static/svg/react-svg/crl.svg | 84 + .../static/svg/react-svg/crystal.svg | 31 + .../static/svg/react-svg/ellipsoidMirror.svg | 98 + .../static/svg/react-svg/emptyElement.svg | 23 + .../static/svg/react-svg/fiber.svg | 31 + .../static/svg/react-svg/grating.svg | 132 + .../static/svg/react-svg/lens.svg | 60 + .../static/svg/react-svg/mask.svg | 456 +++ .../static/svg/react-svg/mirror.svg | 45 + .../static/svg/react-svg/obstacle.svg | 37 + .../static/svg/react-svg/sample.svg | 785 ++++ .../static/svg/react-svg/sphericalMirror.svg | 94 + .../static/svg/react-svg/toroidalMirror.svg | 142 + .../static/svg/react-svg/watch.svg | 105 + .../static/svg/react-svg/zonePlate.svg | 1091 ++++++ sirepo/sim_data/shadow.py | 33 +- sirepo/template/shadow.py | 26 +- sirepo/template/template_common.py | 4 +- 38 files changed, 5188 insertions(+), 1696 deletions(-) create mode 100644 react/src/layout/report/histogram2d.tsx create mode 100644 react/src/layout/shadow/beamlineWatchpointReports.tsx create mode 100755 sirepo/package_data/static/svg/react-svg/aperture.svg create mode 100755 sirepo/package_data/static/svg/react-svg/crl.svg create mode 100755 sirepo/package_data/static/svg/react-svg/crystal.svg create mode 100755 sirepo/package_data/static/svg/react-svg/ellipsoidMirror.svg create mode 100644 sirepo/package_data/static/svg/react-svg/emptyElement.svg create mode 100755 sirepo/package_data/static/svg/react-svg/fiber.svg create mode 100755 sirepo/package_data/static/svg/react-svg/grating.svg create mode 100755 sirepo/package_data/static/svg/react-svg/lens.svg create mode 100755 sirepo/package_data/static/svg/react-svg/mask.svg create mode 100755 sirepo/package_data/static/svg/react-svg/mirror.svg create mode 100755 sirepo/package_data/static/svg/react-svg/obstacle.svg create mode 100755 sirepo/package_data/static/svg/react-svg/sample.svg create mode 100755 sirepo/package_data/static/svg/react-svg/sphericalMirror.svg create mode 100755 sirepo/package_data/static/svg/react-svg/toroidalMirror.svg create mode 100755 sirepo/package_data/static/svg/react-svg/watch.svg create mode 100755 sirepo/package_data/static/svg/react-svg/zonePlate.svg diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 7de82fd9e1..720ebce52f 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -56,7 +56,6 @@ export function FormStateInitializer(props) { formSelectors }) - //let modelNames = Object.keys(schema.models); let modelNames = models.getModelNames(store.getState()); useEffect(() => { @@ -74,7 +73,7 @@ export function FormStateInitializer(props) { if(!modelSchema) { throw new Error(`could not get schema for model=${modelName}`); } - formState.updateModel(modelName, formStateFromModel(value, modelSchema)); + formState.updateModel(modelName, formStateFromModel(value, modelSchema, schema)); }); updateHasInit(true); diff --git a/react/src/component/reusable/graph2d.tsx b/react/src/component/reusable/graph2d.tsx index 758ba1cc5e..21c669938c 100644 --- a/react/src/component/reusable/graph2d.tsx +++ b/react/src/component/reusable/graph2d.tsx @@ -93,9 +93,11 @@ export function Graph2d(props: Graph2dConfig) { nice: true }); + let legendPlots = plots.filter(p => !!p.label); + let legendScale = Scale.scaleOrdinal({ - domain: plots.map(plot => plot.label), - range: plots.map(plot => plot.color) + domain: legendPlots.map(plot => plot.label), + range: legendPlots.map(plot => plot.color) }) let toPath = (plot, index) => { diff --git a/react/src/data/accessor.ts b/react/src/data/accessor.ts index 0d8c2833b0..2c6dedfacd 100644 --- a/react/src/data/accessor.ts +++ b/react/src/data/accessor.ts @@ -1,3 +1,4 @@ +import { ModelStates } from "../store/models"; import { Dependency } from "./dependency"; import { AbstractModelsWrapper } from "./wrapper"; @@ -25,7 +26,7 @@ export class ModelsAccessor { } getFieldValue = (dependency: Dependency): F => { - return this.modelsWrapper.getFieldFromModel(dependency.fieldName, this.modelValues[dependency.modelName]); + return this.modelsWrapper.getFieldFromModel(dependency.fieldName, this.getModelValue(dependency.modelName)); } getModelValue = (modelName: string): M => { diff --git a/react/src/data/dependency.ts b/react/src/data/dependency.ts index c7b8eab14f..cdcd2d06f8 100644 --- a/react/src/data/dependency.ts +++ b/react/src/data/dependency.ts @@ -1,22 +1,28 @@ export class Dependency { modelName: string; fieldName: string; + index?: number; + subFieldName?: string; constructor(dependencyString: string) { - let { modelName, fieldName } = this.mapDependencyNameToParts(dependencyString); + let { modelName, fieldName, index, subFieldName } = this.mapDependencyNameToParts(dependencyString); this.modelName = modelName; this.fieldName = fieldName; + this.index = index; + this.subFieldName = subFieldName; } - mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string } = (dep) => { - let [modelName, fieldName] = dep.split('.').filter((s: string) => s && s.length > 0); + mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string, index?: number, subFieldName?: string } = (dep) => { + let [modelName, fieldName, index, subFieldName] = dep.split('.').filter((s: string) => s && s.length > 0); return { modelName, - fieldName + fieldName, + index: parseInt(index), + subFieldName } } getDependencyString: () => string = () => { - return this.modelName + "." + this.fieldName; + return this.modelName + "." + this.fieldName + (this.index ? `@${this.index}` : ''); } } diff --git a/react/src/data/formController.ts b/react/src/data/formController.ts index 4634550145..f19ced08c5 100644 --- a/react/src/data/formController.ts +++ b/react/src/data/formController.ts @@ -10,25 +10,36 @@ import { InputLayout } from "../layout/input/input"; -export let formStateFromModel = (model: ModelState, modelSchema: SchemaModel) => { +export let formStateFromModel = (model: ModelState, modelSchema: SchemaModel, schema: Schema) => { if(!modelSchema) { throw new Error(`while converting model to form state, model schema was undefiend; model=${JSON.stringify(model)}`); } if(!model) { throw new Error(`while converting model to form state, model was undefined; schema=${JSON.stringify(modelSchema)}`); } - return mapProperties(modelSchema, (fieldName, { type }) => { + // TODO: should this be mapping from schema or from the model being mapped? + return mapProperties(modelSchema, (fieldName, { type, typeName }) => { if(!(fieldName in model)) { throw new Error(`model=${JSON.stringify(model)} was missing field=${fieldName}`) } + if(typeName === "Array") { + let v: {item: ModelState, model: string}[] = model[fieldName] as any[] || []; + return v.map(i => { + return { + item: formStateFromModel(i.item, schema.models[i.model], schema), + model: i.model + } + }) + } + return { valid: type.validate(model[fieldName]), value: type.fromModelValue(model[fieldName]), touched: false, active: true } - }) + }) } export const CFormController = React.createContext(undefined); @@ -79,7 +90,7 @@ export class FormController { // this should make sure that if any part of the reducers are inconsistent / cause mutations // then the form state should remain consistent with saved model copy // TODO: this line has been changed with recent update, evaluate - this.formStatesWrapper.updateModel(modelChanges.modelName, formStateFromModel(m, this.schema.models[modelChanges.modelName])) + this.formStatesWrapper.updateModel(modelChanges.modelName, formStateFromModel(m, this.schema.models[modelChanges.modelName], this.schema)) }) } @@ -97,9 +108,9 @@ export class FormController { cancelChanges = () => { this.formStatesAccessor.modelNames.map(modelName => { - this.formStatesWrapper.updateModel(modelName, formStateFromModel( + return this.formStatesWrapper.updateModel(modelName, formStateFromModel( this.modelStatesAccessor.getModelValue(modelName), - this.schema.models[modelName])); + this.schema.models[modelName], this.schema)); }); } diff --git a/react/src/data/wrapper.ts b/react/src/data/wrapper.ts index d36f9083a2..2211d46c3d 100644 --- a/react/src/data/wrapper.ts +++ b/react/src/data/wrapper.ts @@ -11,6 +11,31 @@ export abstract class AbstractModelsWrapper { abstract getFieldFromModel(fieldName: string, model: M): F; abstract setFieldInModel(fieldName: string, model: M, value: F): M; + getArraySubField = (fieldName: string, index: number, subFieldName: string, model: M): F => { + let fieldState = this.getFieldFromModel(fieldName, model); + let len = this.getArrayFieldLength(fieldState); + if(index >= len) { + throw new Error(`index=${index} of out bounds=${len}`); + } + + return this.getFieldFromModel(subFieldName, fieldState[index]); + } + + setArraySubField = (fieldName: string, index: number, subFieldName: string, model: M, value: F) => { + let fieldState = this.getFieldFromModel(fieldName, model); + let len = this.getArrayFieldLength(fieldState); + if(index >= len) { + throw new Error(`index=${index} of out bounds=${len}`); + } + + let subModel = fieldState[index]; + this.setFieldInModel(subFieldName, subModel, value); + } + + getArrayFieldLength = (field: F): number => { + return (field as any[] || []).length; + } + updateField = (fieldName: string, modelName: string, state: any, value: F): void => { let model = this.getModel(modelName, state); model = this.setFieldInModel(fieldName, model, value); @@ -140,3 +165,53 @@ export class ModelsWrapper extends AbstractModelsWrapper { }) } } + + +/*export type ModelAliases = { + [key: string]: string +} + +export class ModelsWrapperWithAliases extends AbstractModelsWrapper { + private reverseAliases: ModelAliases = undefined; + constructor(private parent: AbstractModelsWrapper, private aliases: ModelAliases) { + super(); + this.reverseAliases = Object.fromEntries(Object.entries(this.aliases).map(([name, value]) => [value, name])); + } + + private getAliasedModelName = (mn: string): string => { + if(mn in this.aliases) { + return this.aliases[mn]; + } + return mn; + } + + private getInverseAliasedModelName = (mn: string): string => { + if(mn in this.reverseAliases) { + return this.reverseAliases[mn]; + } + return mn; + } + + getModel(modelName: string, state: any): M { + return this.parent.getModel(this.getAliasedModelName(modelName), state); + } + + hookModel(modelName: string): M { + return this.parent.hookModel(this.getAliasedModelName(modelName)); + } + + updateModel(modelName: string, value: M): void { + return this.parent.updateModel(this.getAliasedModelName(modelName), value); + } + + getFieldFromModel(fieldName: string, model: M): F { + return this.parent.getFieldFromModel(fieldName, model); + } + + setFieldInModel(fieldName: string, model: M, value: F): M { + return this.parent.setFieldInModel(fieldName, model, value); + } +}*/ + + + diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 6c69651540..573a408246 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -1,7 +1,12 @@ -import React from "react"; +import React, { useContext } from "react"; import { FunctionComponent } from "react"; +import { ModelsAccessor } from "../data/accessor"; import { Dependency } from "../data/dependency"; +import { CFormStateWrapper } from "../data/wrapper"; +import { FormModelState } from "../store/formState"; +import { CRouteHelper } from "../utility/route"; import { SchemaLayout } from "../utility/schema"; +import { ArrayField } from "./input/array"; import { Layout, LayoutProps } from "./layout"; import { createLayouts } from "./layouts"; @@ -12,6 +17,7 @@ export type BeamlineElement = { } export type BeamlineConfig = { + beamlineDependency: string, elements: BeamlineElement[] } @@ -24,21 +30,48 @@ export class BeamlineLayout extends Layout { } getFormDependencies(): Dependency[] { - return []; + return [new Dependency(this.config.beamlineDependency)]; } component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { - let elementThumbnails = this.elements.map(e => { - return ( -
- - + let routeHelper = useContext(CRouteHelper); + let formStateWrapper = useContext(CFormStateWrapper); + let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); + + let accessor = new ModelsAccessor(formStateWrapper, [beamlineDependency]); + + let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; + let elementThumbnails = this.elements.map((e, i) => { + return ( +
+
+ +
+

{e.name}

) }) return ( - <> + <> +
+ {elementThumbnails} +
+
+
+

+ beamline definition area +
+ + + click optical elements to define the beamline + + +

+
+ +
+ ) } } diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index 9b9111441f..45393e1ff6 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -15,6 +15,19 @@ import { useStore } from "react-redux"; import { CSchema } from "../data/appwrapper"; import { ValueSelectors } from "../utility/string"; +export function FormControllerElement(props: {children?: React.ReactNode, dependencies: Dependency[]}) { + let formState = useContext(CFormStateWrapper); + let schema = useContext(CSchema); + let modelsWrapper = useContext(CModelsWrapper); + let formController = new FormController(formState, modelsWrapper, props.dependencies, schema); + + return ( + + { props.children } + + ) +} + export function LayoutWithFormController(Child: LayoutType): LayoutType { return class extends Child { constructor(config: C) { @@ -24,30 +37,13 @@ export function LayoutWithFormController(Child: LayoutType): LayoutT this.component = (props) => { let ChildComponent = childComponent; - let FormComponent = this.formComponent; return ( - + - + ) }; } - - formComponent = (props: LayoutProps

) => { - let formState = useContext(CFormStateWrapper); - let schema = useContext(CSchema); - let modelsWrapper = useContext(CModelsWrapper); - - let dependencies = this.getFormDependencies(); - - let formController = new FormController(formState, modelsWrapper, dependencies, schema); - - return ( - - { props.children } - - ) - }; }; } diff --git a/react/src/layout/input/array.tsx b/react/src/layout/input/array.tsx index c623df8ae0..5b060a4697 100644 --- a/react/src/layout/input/array.tsx +++ b/react/src/layout/input/array.tsx @@ -1,7 +1,14 @@ import { InputConfigBase, InputLayout } from "./input"; +export type ArrayModelElement = { + item: T, + model: string +} + +export type ArrayField = ArrayModelElement[] + export type ArrayInputConfig = { - models: string[] + } & InputConfigBase // TODO: garsuga, implement diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index 5b0746bd51..59ec8f2be6 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -15,6 +15,9 @@ import { SchemaLayout } from "../utility/schema"; import { TextLayout } from "./text"; import { HorizontalStackLayout, VerticalStackLayout } from "./arrange/stack"; import { WaterfallLayout } from "./arrange/waterfall"; +import { Histogram2dFromApi } from "./report/histogram2d"; +import { BeamlineWatchpointReports } from "./shadow/beamlineWatchpointReports"; +import { BeamlineLayout } from "./beamline"; // TODO rename to LayoutsWrapper @@ -32,13 +35,16 @@ class LayoutWrapper { heatplot: LayoutWithDownloadButton(HeatplotFromApi), graph2dPlain: Graph2dFromApi, heatplotPlain: HeatplotFromApi, + histogram2d: Histogram2dFromApi, navTabs: NavTabsLayout, table: TableFromApi, startSimulation: SimulationStartLayout, text: TextLayout, hStack: HorizontalStackLayout, vStack: VerticalStackLayout, - waterfall: WaterfallLayout + waterfall: WaterfallLayout, + beamlineWatchpointReports: BeamlineWatchpointReports, + beamline: BeamlineLayout } constructor () { diff --git a/react/src/layout/report/histogram2d.tsx b/react/src/layout/report/histogram2d.tsx new file mode 100644 index 0000000000..b6d4ca1769 --- /dev/null +++ b/react/src/layout/report/histogram2d.tsx @@ -0,0 +1,85 @@ +import React from "react"; +import { Graph2d, Graph2dConfig } from "../../component/reusable/graph2d"; +import { Point2d } from "../../types"; +import { LayoutProps } from "../layout"; +import { ReportVisual, ReportVisualProps } from "../report"; + +export type Histogram2dConfigApi = { + points: number[], + title: string, + x_label: string, + x_range: number[], + y_label: string +} + +export function apiResponseHistogramToGraph2dConfig(cfg: Histogram2dConfigApi): Graph2dConfig { + if(!cfg) return undefined; + + // TODO: put in schema or get from server + let color = "#006699"; + let [xMin, xMax, numPoints] = cfg.x_range; + let xStep = (xMax - xMin) / numPoints; + + let yMin = Math.min(...cfg.points); + let yMax = Math.max(...cfg.points); + + let points = cfg.points.flatMap((v, i): Point2d[] => { + return [ + { + x: xMin + (xStep * i), + y: v + }, + { + x: xMin + (xStep * (i + 1)), + y: v + } + ] + }) + return { + title: cfg.title, + plots: [ + { + color, + label: undefined, + points + } + ], + xLabel: cfg.x_label, + yLabel: cfg.y_label, + xRange: { + min: xMin, + max: xMax + }, + yRange: { + min: yMin, + max: yMax + } + } +} + +export class Histogram2dFromApi extends ReportVisual { + getConfigFromApiResponse(apiReponse: Histogram2dConfigApi): Graph2dConfig { + return apiResponseHistogramToGraph2dConfig(apiReponse); + } + + canShow(apiResponse: Histogram2dConfigApi): boolean { + return !!this.getConfigFromApiResponse(apiResponse); + } + + getFormDependencies = () => { + return []; + } + + component = (props: LayoutProps<{}> & ReportVisualProps) => { + let { data, model } = props; + if(!data) { + throw new Error("histogram2d received falsy data prop"); + } + + // TODO: extras from model + + return ( + + ) + } +} diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx new file mode 100644 index 0000000000..29b5d78231 --- /dev/null +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -0,0 +1,21 @@ +import React from "react"; +import { FunctionComponent, useContext } from "react"; +import { ModelsAccessor } from "../../data/accessor"; +import { Dependency } from "../../data/dependency"; +import { CFormStateWrapper } from "../../data/wrapper"; +import { SchemaLayout } from "../../utility/schema"; +import { Layout } from "../layout"; +import { LAYOUTS } from "../layouts"; + +export class BeamlineWatchpointReports extends Layout<{}, {}> { + getFormDependencies(): Dependency[] { + return []; + } + + component: FunctionComponent<{ [key: string]: any; }> = (props) => { + let b = new Dependency("watchpointReports.reports"); + let formStateWrapper = useContext(CFormStateWrapper); + let accessor = new ModelsAccessor(formStateWrapper, [b]); + return (<>); + }; +} diff --git a/react/src/utility/download.ts b/react/src/utility/download.ts index ea481d52cc..341e5b929b 100644 --- a/react/src/utility/download.ts +++ b/react/src/utility/download.ts @@ -12,5 +12,6 @@ export function downloadAs(blob: Blob, fileName: string) { export function getAttachmentFileName(response: Response) { let pattern = /filename=["]?([\w.\-_]+)["]?/g let match = pattern.exec(response.headers.get('content-disposition')); + console.log("match", match); return match[1]; } diff --git a/react/src/utility/schema.ts b/react/src/utility/schema.ts index c1f15f65f7..b5f435d934 100644 --- a/react/src/utility/schema.ts +++ b/react/src/utility/schema.ts @@ -46,6 +46,7 @@ export type SchemaLayout = SchemaLayoutJson; export type SchemaField = { displayName: string, type: InputLayout, + typeName: string, defaultValue?: T, description?: string, shown?: string, @@ -144,7 +145,7 @@ export function compileSchemaFromJson(schemaObj: SchemaJson): Schema { let missingTypeNames = []; models = mapProperties(schemaObj.model, (modelName, modelObj) => { - return mapProperties(modelObj, (fieldName, field) => { + return mapProperties(modelObj, (fieldName, field): SchemaField => { let { displayName, type: typeName, defaultValue, description, shown, min, max } = field; let type = types[typeName]; if(!typeName) { @@ -156,6 +157,7 @@ export function compileSchemaFromJson(schemaObj: SchemaJson): Schema { return { displayName, type, + typeName, shown, defaultValue, description, diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index b8eac06bf0..5c866dac18 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -17,6 +17,9 @@ function getStringReplacementPatterns(str: string): RegExpMatchArray[] { export class InterpolationBase { private matches: RegExpMatchArray[]; constructor(private str: string) { + if(!str) { + throw new Error("interpolation base string undefined"); + } this.matches = getStringReplacementPatterns(str); } diff --git a/react/utility/convertschema.ts b/react/utility/convertschema.ts index b3a464f018..aa38c4fe08 100644 --- a/react/utility/convertschema.ts +++ b/react/utility/convertschema.ts @@ -308,6 +308,8 @@ function convertPanel( config['advanced'] = convertPanelContents(view.advanced); } + config['title'] = view.title; + return { layout: "panel", config diff --git a/sirepo/feature_config.py b/sirepo/feature_config.py index 40d6473fb8..6c4f513642 100644 --- a/sirepo/feature_config.py +++ b/sirepo/feature_config.py @@ -182,7 +182,7 @@ def b(msg, dev=False): ), # TODO(pjm): myapp can't be in react_sim_types or unit tests fail react_sim_types=( - ("jspec", "genesis", "warppba", "omega", "myapp") + ("jspec", "genesis", "warppba", "omega", "myapp", "shadow") if pkconfig.channel_in("dev") else (), set, diff --git a/sirepo/package_data/static/react-json/common-schema.json b/sirepo/package_data/static/react-json/common-schema.json index d46746cbc3..68a278880a 100644 --- a/sirepo/package_data/static/react-json/common-schema.json +++ b/sirepo/package_data/static/react-json/common-schema.json @@ -41,6 +41,16 @@ "type": "String", "defaultValue": "" } + }, + "panelState": { + "hidden": { + "displayName": "Hidden Panels", + "type": "PanelArray", + "defaultValue": [] + } + }, + "runSettings": { + } }, "constants": { @@ -52,6 +62,9 @@ "plansUrl": "/en/plans.html" }, "type": { + "PanelArray": { + "base": "Array" + }, "String": { "base": "String", "config": { @@ -338,6 +351,7 @@ "simulationData": "/simulation/:simulation_type/:simulation_id/:pretty/?:section", "simulationFrame": "/simulation-frame/:frame_id", "simulationSchema": "/simulation-schema", + "svg": "/static/svg/react-svg/:fileName", "srUnit": "/ srunit", "srwLight": "/light", "statefulCompute": "/stateful-compute", diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index ad2b2ebf0c..9e73381d2b 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -1833,6 +1833,10 @@ } }, "watchpointReport": { + "id": { + "displayName": "Beamline Element ID", + "type": "Integer" + }, "x": { "displayName": "Value to Plot", "type": "ColumnValue", @@ -1894,6 +1898,13 @@ "defaultValue": "" } }, + "watchpointReports": { + "reports": { + "displayname": "Watchpoint Reports", + "type": "WatchpointArray", + "defaultValue": [] + } + }, "wiggler": { "ph1": { "displayName": "Minimum Energy [eV]", @@ -2085,21 +2096,7 @@ } }, "BeamlineElementsArray": { - "base": "Array", - "config": { - "models": [ - "aperture", - "crl", - "crystal", - "emptyElement", - "grating", - "lens", - "mirror", - "obstacle", - "watch", - "zonePlate" - ] - } + "base": "Array" }, "BeamShift": { "base": "Enum", @@ -3375,6 +3372,9 @@ ] } }, + "WatchpointArray": { + "base": "Array" + }, "ZonePlateType": { "base": "Enum", "config": { @@ -3423,47 +3423,829 @@ "config": { "tabs": [ { - "name": "Source", + "name": "source", + "title": "Source", "items": [ { - "layout": "panel", + "layout": "waterfall", "config": { - "title": "Geometric Source", - "basic": [ + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "items": [ { - "layout": "fieldList", + "layout": "panel", "config": { - "fields": [ - "simulation.sourceType", - "geometricSource.fsour", - "geometricSource.wxsou", - "geometricSource.wzsou", - "geometricSource.sigmax", - "geometricSource.sigmaz" + "title": "Geometric Source", + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "geometricSource.fsour", + "geometricSource.wxsou", + "geometricSource.wzsou", + "geometricSource.sigmax", + "geometricSource.sigmaz" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Geometry Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "geometricSource.fsour", + "geometricSource.wxsou", + "geometricSource.wzsou", + "geometricSource.sigmax", + "geometricSource.sigmaz", + "geometricSource.fdistr" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Divergence +X [mrad]", + "fields": [ + "sourceDivergence.hdiv1", + "sourceDivergence.vdiv1" + ] + }, + { + "label": "Horizontal Divergence -X [mrad]", + "fields": [ + "sourceDivergence.hdiv2", + "sourceDivergence.vdiv2" + ] + }, + { + "label": "Horizontal Sigma (X) [mrad]", + "fields": [ + "geometricSource.sigdix", + "geometricSource.sigdiz" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "geometricSource.cone_min", + "geometricSource.cone_max", + "geometricSource.fsource_depth", + "geometricSource.wysou", + "geometricSource.sigmay" + ] + } + } + ] + }, + { + "name": "Energy/Polarization Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "geometricSource.f_color", + "geometricSource.singleEnergyValue", + "geometricSource.ph1", + "geometricSource.ph2", + "geometricSource.f_polar", + "geometricSource.f_coher", + "geometricSource.pol_angle", + "geometricSource.pol_deg" + ] + } + } + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } + } + ] + } + ] + } + } ] - } + }, + "_NAME": "geometricSource" + }, + { + "layout": "panel", + "config": { + "title": "Bending Magnet", + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "bendingMagnet.ph1", + "bendingMagnet.ph2", + "electronBeam.bener" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "bendingMagnet.ph1", + "bendingMagnet.ph2" + ] + } + } + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "electronBeam.bener", + "electronBeam.f_pol" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Z" + ], + "rows": [ + { + "label": "X Sigma [µm]", + "fields": [ + "electronBeam.sigmax", + "electronBeam.sigmaz" + ] + }, + { + "label": "X Emittance [nrad]", + "fields": [ + "electronBeam.epsi_x", + "electronBeam.epsi_z" + ] + }, + { + "label": "X Distance From Waist [m]", + "fields": [ + "electronBeam.epsi_dx", + "electronBeam.epsi_dz" + ] + } + ] + } + } + ] + }, + { + "name": "Magnet Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bendingMagnet.calculateFieldMethod", + "bendingMagnet.r_magnet", + "bendingMagnet.magneticField", + "bendingMagnet.fdistr" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Divergence +X [mrad]", + "fields": [ + "sourceDivergence.hdiv1", + "sourceDivergence.vdiv1" + ] + }, + { + "label": "Horizontal Divergence -X [mrad]", + "fields": [ + "sourceDivergence.hdiv2", + "sourceDivergence.vdiv2" + ] + } + ] + } + } + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "bendingMagnet" + }, + { + "layout": "panel", + "config": { + "title": "Undulator", + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "undulatorBeam.energy", + "undulator.select_energy", + "undulator.energy_harmonic", + "undulator.photon_energy", + "undulator.emin", + "undulator.emax", + "undulator.maxangle" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "undulator.select_energy", + "undulator.energy_harmonic", + "undulator.photon_energy", + "undulator.emin", + "undulator.emax", + "undulator.maxangle", + "undulator.ng_e" + ] + } + } + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "undulatorBeam.energy", + "undulatorBeam.energy_spread", + "undulatorBeam.current", + "undulatorBeam.number_of_bunches" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Twiss Parameters", + "Vertical Twiss Parameters" + ], + "rows": [ + { + "label": "Horizontal Emittance [nm]", + "fields": [ + "undulatorBeam.emittance_x", + "undulatorBeam.emittance_y" + ] + }, + { + "label": "Horizontal Beta [m]", + "description": 1e-99, + "fields": [ + "undulatorBeam.beta_x", + "undulatorBeam.beta_y" + ] + }, + { + "label": "Horizontal Alpha [rad]", + "fields": [ + "undulatorBeam.alpha_x", + "undulatorBeam.alpha_y" + ] + }, + { + "label": "Horizontal Dispersion [m]", + "fields": [ + "undulatorBeam.eta_x", + "undulatorBeam.eta_y" + ] + }, + { + "label": "Horizontal Dispersion Derivative [rad]", + "fields": [ + "undulatorBeam.etap_x", + "undulatorBeam.etap_y" + ] + } + ] + } + } + ] + }, + { + "name": "Undulator Properties", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "undulator.period", + "undulator.length" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Deflecting Parameter (K)", + "fields": [ + "undulator.k_horizontal", + "undulator.k_vertical" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "undulator.ng_t", + "undulator.ng_p", + "undulator.ng_j", + "undulator.flag_size", + "undulator.f_coher" + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "undulator" + }, + { + "layout": "panel", + "config": { + "title": "Wiggler", + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.sourceType", + "wiggler.ph1", + "wiggler.ph2", + "electronBeam.bener" + ] + } + } + ], + "advanced": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Basic Settings", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.npoint", + "simulation.istar1", + "wiggler.ph1", + "wiggler.ph2" + ] + } + } + ] + }, + { + "name": "Beam Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "electronBeam.bener" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Z" + ], + "rows": [ + { + "label": "X Sigma [µm]", + "fields": [ + "electronBeam.sigmax", + "electronBeam.sigmaz" + ] + }, + { + "label": "X Emittance [nrad]", + "fields": [ + "electronBeam.epsi_x", + "electronBeam.epsi_z" + ] + }, + { + "label": "X Distance From Waist [m]", + "fields": [ + "electronBeam.epsi_dx", + "electronBeam.epsi_dz" + ] + } + ] + } + } + ] + }, + { + "name": "Wiggler Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "wiggler.b_from", + "wiggler.kValue", + "wiggler.trajFile", + "wiggler.nPer", + "wiggler.per", + "wiggler.shift_x_flag", + "wiggler.shift_x_value", + "wiggler.shift_betax_flag", + "wiggler.shift_betax_value" + ] + } + } + ] + }, + { + "name": "Ray Filter", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "rayFilter.f_bound_sour", + "rayFilter.distance" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Minimum", + "Maximum" + ], + "rows": [ + { + "label": "X Minimum [mm]", + "fields": [ + "rayFilter.x1", + "rayFilter.x2" + ] + }, + { + "label": "Z Minimum [mm]", + "fields": [ + "rayFilter.z1", + "rayFilter.z2" + ] + } + ] + } + } + ] + } + ] + } + } + ] + }, + "_NAME": "wiggler" + }, + { + "layout": "panel", + "config": { + "title": "Histogram", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "histogramReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "histogramReport.*" + ], + "reportLayout": { + "layout": "histogram2d" + } + } + } + ], + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "histogramReport.distanceFromSource", + "histogramReport.column", + "histogramReport.weight", + "histogramReport.histogramBins", + "histogramReport.notes" + ] + } + } + ] + }, + "_NAME": "histogramReport" + }, + { + "layout": "panel", + "config": { + "title": "PlotXY", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "plotXYReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "plotXYReport.*" + ], + "reportLayout": { + "layout": "heatplot" + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "plotXYReport.x", + "plotXYReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "plotXYReport.weight", + "plotXYReport.histogramBins", + "plotXYReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "plotXYReport.horizontalSize", + "plotXYReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "plotXYReport.horizontalOffset", + "plotXYReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "plotXYReport.aspectRatio", + "plotXYReport.colorMap", + "plotXYReport.notes", + "plotXYReport.distanceFromSource" + ] + } + } + ] + }, + "_NAME": "plotXYReport" } - ], - "advanced": [ + ] + } + } + ] + }, + { + "name": "beamline", + "title": "Beamline", + "items": [ + { + "layout": "vStack", + "config": { + "items": [ { - "layout": "tabs", + "layout": "beamline", "config": { - "tabs": [ + "beamlineDependency": "beamline.elements", + "elements": [ { - "name": "Geometry Settings", + "name": "Aperture", + "icon": "aperture.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "simulation.npoint", - "simulation.istar1", - "geometricSource.fsour", - "geometricSource.wxsou", - "geometricSource.wzsou", - "geometricSource.sigmax", - "geometricSource.sigmaz", - "geometricSource.fdistr" + "aperture.title", + "aperture.position", + "aperture.shape" ] } }, @@ -3476,185 +4258,259 @@ ], "rows": [ { - "label": "Horizontal Divergence +X [mrad]", - "fields": [ - "sourceDivergence.hdiv1", - "sourceDivergence.vdiv1" - ] - }, - { - "label": "Horizontal Divergence -X [mrad]", + "label": "Horizontal Size [mm]", "fields": [ - "sourceDivergence.hdiv2", - "sourceDivergence.vdiv2" + "aperture.horizontalSize", + "aperture.verticalSize" ] }, { - "label": "Horizontal Sigma (X) [mrad]", + "label": "Horizontal Offset [mm]", "fields": [ - "geometricSource.sigdix", - "geometricSource.sigdiz" + "aperture.horizontalOffset", + "aperture.verticalOffset" ] } ] } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "geometricSource.cone_min", - "geometricSource.cone_max", - "geometricSource.fsource_depth", - "geometricSource.wysou", - "geometricSource.sigmay" - ] - } } ] }, { - "name": "Energy/Polarization Settings", + "name": "CRL", + "icon": "crl.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "geometricSource.f_color", - "geometricSource.singleEnergyValue", - "geometricSource.ph1", - "geometricSource.ph2", - "geometricSource.f_polar", - "geometricSource.f_coher", - "geometricSource.pol_angle", - "geometricSource.pol_deg" + "crl.title", + "crl.position", + "crl.numberOfLenses", + "crl.numberOfEmptySlots", + "crl.pilingThickness", + "crl.focalDistance", + "crl.fhit_c", + "crl.lensDiameter", + "crl.fmirr", + "crl.rmirr", + "crl.lensThickness", + "crl.useCCC", + "crl.initialCurvature", + "crl.fcyl", + "crl.cil_ang", + "crl.refractionIndex", + "crl.attenuationCoefficient" ] } } ] }, { - "name": "Ray Filter", + "name": "Crystal", + "icon": "crystal.svg", "items": [ { - "layout": "fieldList", - "config": { - "fields": [ - "rayFilter.f_bound_sour", - "rayFilter.distance" - ] - } - }, - { - "layout": "fieldTable", + "layout": "tabs", "config": { - "columns": [ - "Minimum", - "Maximum" - ], - "rows": [ + "tabs": [ { - "label": "X Minimum [mm]", - "fields": [ - "rayFilter.x1", - "rayFilter.x2" + "name": "Misalignment", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Y", + "Z" + ], + "rows": [ + { + "label": "X Offset [mm]", + "fields": [ + "crystal.offx", + "crystal.offy", + "crystal.offz" + ] + }, + { + "label": "X Rotation [CCW, deg]", + "fields": [ + "crystal.x_rot", + "crystal.y_rot", + "crystal.z_rot" + ] + } + ] + } + } ] }, { - "label": "Z Minimum [mm]", - "fields": [ - "rayFilter.z1", - "rayFilter.z2" + "name": "Main Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.title", + "crystal.position", + "crystal.fmirr", + "crystal.f_central", + "crystal.t_incidence", + "crystal.t_reflection", + "crystal.f_phot_cent", + "crystal.phot_cent", + "crystal.r_lambda", + "crystal.alpha" + ] + } + } ] - } - ] - } - } - ] - } - ] - } - } - ] - }, - "_NAME": "geometricSource" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "bendingMagnet.ph1", - "bendingMagnet.ph2", - "electronBeam.bener" - ] - } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Basic Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.npoint", - "simulation.istar1", - "bendingMagnet.ph1", - "bendingMagnet.ph2" - ] - } - } - ] - }, - { - "name": "Beam Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "electronBeam.bener", - "electronBeam.f_pol" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Z" - ], - "rows": [ + }, { - "label": "X Sigma [µm]", - "fields": [ - "electronBeam.sigmax", - "electronBeam.sigmaz" + "name": "Surface Shape", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.f_ext", + "crystal.f_default", + "crystal.ssour", + "crystal.simag", + "crystal.theta", + "crystal.f_side", + "crystal.rmirr", + "crystal.param", + "crystal.axmaj", + "crystal.axmin", + "crystal.ell_the", + "crystal.f_convex", + "crystal.fcyl", + "crystal.cil_ang", + "crystal.r_maj", + "crystal.r_min", + "crystal.f_torus" + ] + } + } ] }, { - "label": "X Emittance [nrad]", - "fields": [ - "electronBeam.epsi_x", - "electronBeam.epsi_z" + "name": "Crystal", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.f_refrac", + "crystal.f_mosaic", + "crystal.f_bragg_a", + "crystal.a_bragg", + "crystal.order", + "crystal.spread_mos", + "crystal.thickness", + "crystal.mosaic_seed", + "crystal.f_johansson", + "crystal.r_johansson" + ] + } + } ] }, { - "label": "X Distance From Waist [m]", - "fields": [ - "electronBeam.epsi_dx", - "electronBeam.epsi_dz" + "name": "Bragg", + "items": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Material of the crystal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "braggMaterial" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Miller's indices" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "braggMillerH", + "braggMillerK", + "braggMillerL" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.braggTemperaturFactor", + "crystal.braggMinEnergy", + "crystal.braggMaxEnergy", + "crystal.braggEnergyStep" + ] + } + } + ] + }, + { + "name": "Dimensions", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "crystal.fhit_c", + "crystal.fshape", + "crystal.halfWidthX1", + "crystal.halfWidthX2", + "crystal.halfLengthY1", + "crystal.halfLengthY2", + "crystal.externalOutlineMajorAxis", + "crystal.externalOutlineMinorAxis", + "crystal.internalOutlineMajorAxis", + "crystal.internalOutlineMinorAxis" + ] + } + } ] } ] @@ -3663,194 +4519,413 @@ ] }, { - "name": "Magnet Parameters", + "name": "Empty Element", + "icon": "emptyElement.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "bendingMagnet.calculateFieldMethod", - "bendingMagnet.r_magnet", - "bendingMagnet.magneticField", - "bendingMagnet.fdistr" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Divergence +X [mrad]", - "fields": [ - "sourceDivergence.hdiv1", - "sourceDivergence.vdiv1" - ] - }, - { - "label": "Horizontal Divergence -X [mrad]", - "fields": [ - "sourceDivergence.hdiv2", - "sourceDivergence.vdiv2" - ] - } + "emptyElement.title", + "emptyElement.position", + "emptyElement.alpha" ] } } ] }, { - "name": "Ray Filter", + "name": "Grating", + "icon": "grating.svg", "items": [ { - "layout": "fieldList", - "config": { - "fields": [ - "rayFilter.f_bound_sour", - "rayFilter.distance" - ] - } - }, - { - "layout": "fieldTable", + "layout": "tabs", "config": { - "columns": [ - "Minimum", - "Maximum" - ], - "rows": [ + "tabs": [ { - "label": "X Minimum [mm]", - "fields": [ - "rayFilter.x1", - "rayFilter.x2" + "name": "Misalignment", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Y", + "Z" + ], + "rows": [ + { + "label": "X Offset [mm]", + "fields": [ + "grating.offx", + "grating.offy", + "grating.offz" + ] + }, + { + "label": "X Rotation [CCW, deg]", + "fields": [ + "grating.x_rot", + "grating.y_rot", + "grating.z_rot" + ] + } + ] + } + } ] }, { - "label": "Z Minimum [mm]", - "fields": [ - "rayFilter.z1", - "rayFilter.z2" + "name": "Main Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.title", + "grating.position", + "grating.fmirr", + "grating.f_central", + "grating.f_phot_cent", + "grating.phot_cent", + "grating.r_lambda", + "grating.t_incidence", + "grating.t_reflection", + "grating.alpha" + ] + } + } + ] + }, + { + "name": "Surface Shape", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.f_ext", + "grating.f_default", + "grating.ssour", + "grating.simag", + "grating.theta", + "grating.f_side", + "grating.rmirr", + "grating.param", + "grating.axmaj", + "grating.axmin", + "grating.ell_the", + "grating.f_convex", + "grating.fcyl", + "grating.cil_ang", + "grating.r_maj", + "grating.r_min", + "grating.f_torus" + ] + } + } + ] + }, + { + "name": "Grating", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.f_ruling", + "grating.rulingDensity", + "grating.rulingDensityCenter", + "grating.rulingDensityPolynomial" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Entrance", + "Exit" + ], + "rows": [ + { + "label": "Entrance Slit Distance [mm]", + "fields": [ + "grating.holo_r1", + "grating.holo_r2" + ] + }, + { + "label": "Entrance Slit Incidence Angle [deg]", + "fields": [ + "grating.holo_del", + "grating.holo_gam" + ] + }, + { + "label": "Entrance Slit Rotation Angle [deg]", + "fields": [ + "grating.holo_rt1", + "grating.holo_rt2" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.f_pw", + "grating.f_pw_c", + "grating.f_virtual", + "grating.holo_w", + "grating.azim_fan", + "grating.dist_fan", + "grating.coma_fac", + "grating.rul_a1", + "grating.rul_a2", + "grating.rul_a3", + "grating.rul_a4", + "grating.f_rul_abs" + ] + } + } + ] + }, + { + "name": "Diffraction", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.order", + "grating.f_mono", + "grating.f_hunt", + "grating.hunt_h", + "grating.hunt_l", + "grating.blaze" + ] + } + } + ] + }, + { + "name": "Dimensions", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "grating.fhit_c", + "grating.fshape", + "grating.halfWidthX1", + "grating.halfWidthX2", + "grating.halfLengthY1", + "grating.halfLengthY2", + "grating.externalOutlineMajorAxis", + "grating.externalOutlineMinorAxis", + "grating.internalOutlineMajorAxis", + "grating.internalOutlineMinorAxis" + ] + } + } ] } ] } } ] - } - ] - } - } - ] - }, - "_NAME": "bendingMagnet" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "undulatorBeam.energy", - "undulator.select_energy", - "undulator.energy_harmonic", - "undulator.photon_energy", - "undulator.emin", - "undulator.emax", - "undulator.maxangle" - ] - } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ + }, { - "name": "Basic Settings", + "name": "Lens", + "icon": "lens.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "simulation.npoint", - "simulation.istar1", - "undulator.select_energy", - "undulator.energy_harmonic", - "undulator.photon_energy", - "undulator.emin", - "undulator.emax", - "undulator.maxangle", - "undulator.ng_e" + "lens.title", + "lens.position", + "lens.focal_x", + "lens.focal_z" ] } } ] }, { - "name": "Beam Parameters", + "name": "Mirror", + "icon": "mirror.svg", "items": [ { - "layout": "fieldList", - "config": { - "fields": [ - "undulatorBeam.energy", - "undulatorBeam.energy_spread", - "undulatorBeam.current", - "undulatorBeam.number_of_bunches" - ] - } - }, - { - "layout": "fieldTable", + "layout": "tabs", "config": { - "columns": [ - "Horizontal Twiss Parameters", - "Vertical Twiss Parameters" - ], - "rows": [ + "tabs": [ { - "label": "Horizontal Emittance [nm]", - "fields": [ - "undulatorBeam.emittance_x", - "undulatorBeam.emittance_y" + "name": "Misalignment", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "X", + "Y", + "Z" + ], + "rows": [ + { + "label": "X Offset [mm]", + "fields": [ + "mirror.offx", + "mirror.offy", + "mirror.offz" + ] + }, + { + "label": "X Rotation [CCW, deg]", + "fields": [ + "mirror.x_rot", + "mirror.y_rot", + "mirror.z_rot" + ] + } + ] + } + } ] }, { - "label": "Horizontal Beta [m]", - "description": 1e-99, - "fields": [ - "undulatorBeam.beta_x", - "undulatorBeam.beta_y" + "name": "Main Parameters", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.title", + "mirror.position", + "mirror.fmirr", + "mirror.t_incidence", + "mirror.alpha" + ] + } + } ] }, { - "label": "Horizontal Alpha [rad]", - "fields": [ - "undulatorBeam.alpha_x", - "undulatorBeam.alpha_y" + "name": "Surface Shape", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.f_ext", + "mirror.f_default", + "mirror.ssour", + "mirror.simag", + "mirror.theta", + "mirror.f_side", + "mirror.rmirr", + "mirror.param", + "mirror.axmaj", + "mirror.axmin", + "mirror.ell_the", + "mirror.f_convex", + "mirror.fcyl", + "mirror.cil_ang", + "mirror.r_maj", + "mirror.r_min", + "mirror.f_torus" + ] + } + } ] }, { - "label": "Horizontal Dispersion [m]", - "fields": [ - "undulatorBeam.eta_x", - "undulatorBeam.eta_y" + "name": "Reflectivity", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.f_reflec", + "mirror.f_refl", + "mirror.reflectivityMinEnergy", + "mirror.reflectivityMaxEnergy", + "mirror.prereflStep", + "mirror.prereflElement", + "mirror.prereflDensity", + "mirror.f_thick" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Material", + "Density [g/m³]" + ], + "rows": [ + { + "label": "Material Substrate", + "fields": [ + "mirror.mlayerSubstrateMaterial", + "mirror.mlayerSubstrateDensity" + ] + }, + { + "label": "Material Even Sublayer", + "fields": [ + "mirror.mlayerEvenSublayerMaterial", + "mirror.mlayerEvenSublayerDensity" + ] + }, + { + "label": "Material Odd Sublayer", + "fields": [ + "mirror.mlayerOddSublayerMaterial", + "mirror.mlayerOddSublayerDensity" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.mlayerBilayerNumber", + "mirror.mlayerBilayerThickness", + "mirror.mlayerGammaRatio", + "mirror.mlayerEvenRoughness", + "mirror.mlayerOddRoughness" + ] + } + } ] }, { - "label": "Horizontal Dispersion Derivative [rad]", - "fields": [ - "undulatorBeam.etap_x", - "undulatorBeam.etap_y" + "name": "Dimensions", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "mirror.fhit_c", + "mirror.fshape", + "mirror.halfWidthX1", + "mirror.halfWidthX2", + "mirror.halfLengthY1", + "mirror.halfLengthY2", + "mirror.externalOutlineMajorAxis", + "mirror.externalOutlineMinorAxis", + "mirror.internalOutlineMajorAxis", + "mirror.internalOutlineMinorAxis" + ] + } + } ] } ] @@ -3859,14 +4934,16 @@ ] }, { - "name": "Undulator Properties", + "name": "Obstacle", + "icon": "obstacle.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "undulator.period", - "undulator.length" + "obstacle.title", + "obstacle.position", + "obstacle.shape" ] } }, @@ -3879,111 +4956,17 @@ ], "rows": [ { - "label": "Horizontal Deflecting Parameter (K)", - "fields": [ - "undulator.k_horizontal", - "undulator.k_vertical" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "undulator.ng_t", - "undulator.ng_p", - "undulator.ng_j", - "undulator.flag_size", - "undulator.f_coher" - ] - } - } - ] - } - ] - } - } - ] - }, - "_NAME": "undulator" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.sourceType", - "wiggler.ph1", - "wiggler.ph2", - "electronBeam.bener" - ] - } - } - ], - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Basic Settings", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.npoint", - "simulation.istar1", - "wiggler.ph1", - "wiggler.ph2" - ] - } - } - ] - }, - { - "name": "Beam Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "electronBeam.bener" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Z" - ], - "rows": [ - { - "label": "X Sigma [µm]", - "fields": [ - "electronBeam.sigmax", - "electronBeam.sigmaz" - ] - }, - { - "label": "X Emittance [nrad]", + "label": "Horizontal Size [mm]", "fields": [ - "electronBeam.epsi_x", - "electronBeam.epsi_z" + "obstacle.horizontalSize", + "obstacle.verticalSize" ] }, { - "label": "X Distance From Waist [m]", + "label": "Horizontal Offset [mm]", "fields": [ - "electronBeam.epsi_dx", - "electronBeam.epsi_dz" + "obstacle.horizontalOffset", + "obstacle.verticalOffset" ] } ] @@ -3992,60 +4975,39 @@ ] }, { - "name": "Wiggler Parameters", + "name": "Watch", + "icon": "watch.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "wiggler.b_from", - "wiggler.kValue", - "wiggler.trajFile", - "wiggler.nPer", - "wiggler.per", - "wiggler.shift_x_flag", - "wiggler.shift_x_value", - "wiggler.shift_betax_flag", - "wiggler.shift_betax_value" + "watch.title", + "watch.position" ] } } ] }, { - "name": "Ray Filter", + "name": "Zone Plate", + "icon": "zonePlate.svg", "items": [ { "layout": "fieldList", "config": { "fields": [ - "rayFilter.f_bound_sour", - "rayFilter.distance" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Minimum", - "Maximum" - ], - "rows": [ - { - "label": "X Minimum [mm]", - "fields": [ - "rayFilter.x1", - "rayFilter.x2" - ] - }, - { - "label": "Z Minimum [mm]", - "fields": [ - "rayFilter.z1", - "rayFilter.z2" - ] - } + "zonePlate.title", + "zonePlate.position", + "zonePlate.zone_plate_type", + "zonePlate.width_coating", + "zonePlate.height", + "zonePlate.diameter", + "zonePlate.b_min", + "zonePlate.zone_plate_material", + "zonePlate.template_material", + "zonePlate.n_points", + "zonePlate.last_index" ] } } @@ -4053,1223 +5015,176 @@ } ] } - } - ] - }, - "_NAME": "wiggler" - }, - { - "layout": "panel", - "config": { - "title": "Histogram", - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "histogramReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "histogramReport.*" - ], - "reportLayout": { - "layout": "graph2d" - } - } - } - ], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "histogramReport.distanceFromSource", - "histogramReport.column", - "histogramReport.weight", - "histogramReport.histogramBins", - "histogramReport.notes" - ] - } - } - ] - }, - "_NAME": "histogramReport" - }, - { - "layout": "panel", - "config": { - "title": "PlotXY", - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "plotXYReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "plotXYReport.*" - ], - "reportLayout": { - "layout": "heatplot" - } - } - } - ], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Value to Plot", - "fields": [ - "plotXYReport.x", - "plotXYReport.y" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "plotXYReport.weight", - "plotXYReport.histogramBins", - "plotXYReport.overrideSize" - ] - } }, { - "layout": "fieldTable", + "layout": "waterfall", "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "plotXYReport.horizontalSize", - "plotXYReport.verticalSize" - ] - }, + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "items": [ { - "label": "Horizontal Offset [mm]", - "fields": [ - "plotXYReport.horizontalOffset", - "plotXYReport.verticalOffset" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "plotXYReport.aspectRatio", - "plotXYReport.colorMap", - "plotXYReport.notes", - "plotXYReport.distanceFromSource" - ] - } - } - ] - }, - "_NAME": "plotXYReport" - } - ] - }, - { - "name": "Beamline", - "items": [ - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "initialIntensityReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "initialIntensityReport.*" - ], - "reportLayout": { - "layout": "heatplot" - } - } - } - ], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Value to Plot", - "fields": [ - "initialIntensityReport.x", - "initialIntensityReport.y" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "initialIntensityReport.weight", - "initialIntensityReport.histogramBins", - "initialIntensityReport.overrideSize" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "initialIntensityReport.horizontalSize", - "initialIntensityReport.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "initialIntensityReport.horizontalOffset", - "initialIntensityReport.verticalOffset" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "initialIntensityReport.aspectRatio", - "initialIntensityReport.colorMap", - "initialIntensityReport.notes" - ] - } - } - ] - }, - "_NAME": "initialIntensityReport" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "watchpointReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "watchpointReport.*" - ], - "reportLayout": { - "layout": "heatplot" - } - } - } - ], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Value to Plot", - "fields": [ - "watchpointReport.x", - "watchpointReport.y" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "watchpointReport.weight", - "watchpointReport.histogramBins", - "watchpointReport.overrideSize" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal Axis", - "Vertical Axis" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "watchpointReport.horizontalSize", - "watchpointReport.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "watchpointReport.horizontalOffset", - "watchpointReport.verticalOffset" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "watchpointReport.aspectRatio", - "watchpointReport.colorMap", - "watchpointReport.notes" - ] - } - } - ] - }, - "_NAME": "watchpointReport" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "beamStatisticsReport", - "dependencies": [ - "beamline.*", - "bendingMagnet.*", - "electronBeam.*", - "geometricSource.*", - "rayFilter.*", - "simulation.*", - "sourceDivergence.*", - "undulator.*", - "undulatorBeam.*", - "wiggler.*", - "beamStatisticsReport.*" - ], - "reportLayout": { - "layout": "graph2d" - } - } - } - ], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "beamStatisticsReport.y1", - "beamStatisticsReport.y2", - "beamStatisticsReport.y3", - "beamStatisticsReport.epsilon", - "beamStatisticsReport.driftDivisions", - "beamStatisticsReport.includeApertures", - "beamStatisticsReport.k_apert_x", - "beamStatisticsReport.k_apert_y", - "beamStatisticsReport.notes" - ] - } - } - ] - }, - "_NAME": "beamStatisticsReport" - } - ] - } - ] - } - - }, - { - "layout": "panel", - "config": { - "basic": [], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "aperture.title", - "aperture.position", - "aperture.shape" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "aperture.horizontalSize", - "aperture.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "aperture.horizontalOffset", - "aperture.verticalOffset" - ] - } - ] - } - } - ] - }, - "_NAME": "aperture" - }, - { - "layout": "panel", - "config": { - "basic": [], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "crl.title", - "crl.position", - "crl.numberOfLenses", - "crl.numberOfEmptySlots", - "crl.pilingThickness", - "crl.focalDistance", - "crl.fhit_c", - "crl.lensDiameter", - "crl.fmirr", - "crl.rmirr", - "crl.lensThickness", - "crl.useCCC", - "crl.initialCurvature", - "crl.fcyl", - "crl.cil_ang", - "crl.refractionIndex", - "crl.attenuationCoefficient" - ] - } - } - ] - }, - "_NAME": "crl" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Misalignment", - "items": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Y", - "Z" - ], - "rows": [ - { - "label": "X Offset [mm]", - "fields": [ - "crystal.offx", - "crystal.offy", - "crystal.offz" - ] - }, - { - "label": "X Rotation [CCW, deg]", - "fields": [ - "crystal.x_rot", - "crystal.y_rot", - "crystal.z_rot" - ] - } - ] - } - } - ] - }, - { - "name": "Main Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "crystal.title", - "crystal.position", - "crystal.fmirr", - "crystal.f_central", - "crystal.t_incidence", - "crystal.t_reflection", - "crystal.f_phot_cent", - "crystal.phot_cent", - "crystal.r_lambda", - "crystal.alpha" - ] - } - } - ] - }, - { - "name": "Surface Shape", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "crystal.f_ext", - "crystal.f_default", - "crystal.ssour", - "crystal.simag", - "crystal.theta", - "crystal.f_side", - "crystal.rmirr", - "crystal.param", - "crystal.axmaj", - "crystal.axmin", - "crystal.ell_the", - "crystal.f_convex", - "crystal.fcyl", - "crystal.cil_ang", - "crystal.r_maj", - "crystal.r_min", - "crystal.f_torus" - ] - } - } - ] - }, - { - "name": "Crystal", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "crystal.f_refrac", - "crystal.f_mosaic", - "crystal.f_bragg_a", - "crystal.a_bragg", - "crystal.order", - "crystal.spread_mos", - "crystal.thickness", - "crystal.mosaic_seed", - "crystal.f_johansson", - "crystal.r_johansson" - ] - } - } - ] - }, - { - "name": "Bragg", - "items": [ - { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", + "layout": "panel", "config": { - "items": [ + "title": "Initial Intensity Report", + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "initialIntensityReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "initialIntensityReport.*" + ], + "reportLayout": { + "layout": "heatplot" + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "initialIntensityReport.x", + "initialIntensityReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "initialIntensityReport.weight", + "initialIntensityReport.histogramBins", + "initialIntensityReport.overrideSize" + ] + } + }, { - "layout": "text", + "layout": "fieldTable", "config": { - "type": "header", - "align": "left", - "text": "Material of the crystal" + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "initialIntensityReport.horizontalSize", + "initialIntensityReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "initialIntensityReport.horizontalOffset", + "initialIntensityReport.verticalOffset" + ] + } + ] } }, { "layout": "fieldList", "config": { "fields": [ - "braggMaterial" + "initialIntensityReport.aspectRatio", + "initialIntensityReport.colorMap", + "initialIntensityReport.notes" ] } } ] - } + }, + "_NAME": "initialIntensityReport" }, { - "layout": "vStack", + "layout": "panel", "config": { - "items": [ + "title": "Beam Statistics", + "basic": [ { - "layout": "text", + "layout": "autoRunReport", "config": { - "type": "header", - "align": "left", - "text": "Miller's indices" + "report": "beamStatisticsReport", + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "beamStatisticsReport.*" + ], + "reportLayout": { + "layout": "graph2d" + } } - }, + } + ], + "advanced": [ { "layout": "fieldList", "config": { "fields": [ - "braggMillerH", - "braggMillerK", - "braggMillerL" + "beamStatisticsReport.y1", + "beamStatisticsReport.y2", + "beamStatisticsReport.y3", + "beamStatisticsReport.epsilon", + "beamStatisticsReport.driftDivisions", + "beamStatisticsReport.includeApertures", + "beamStatisticsReport.k_apert_x", + "beamStatisticsReport.k_apert_y", + "beamStatisticsReport.notes" ] } } ] - } + }, + "_NAME": "beamStatisticsReport" } ] } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "crystal.braggTemperaturFactor", - "crystal.braggMinEnergy", - "crystal.braggMaxEnergy", - "crystal.braggEnergyStep" - ] - } - } - ] - }, - { - "name": "Dimensions", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "crystal.fhit_c", - "crystal.fshape", - "crystal.halfWidthX1", - "crystal.halfWidthX2", - "crystal.halfLengthY1", - "crystal.halfLengthY2", - "crystal.externalOutlineMajorAxis", - "crystal.externalOutlineMinorAxis", - "crystal.internalOutlineMajorAxis", - "crystal.internalOutlineMinorAxis" - ] - } } ] } - ] - } - } - ] - }, - "_NAME": "crystal" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "emptyElement.title", - "emptyElement.position", - "emptyElement.alpha" - ] - } - } - ] - }, - "_NAME": "emptyElement" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Misalignment", - "items": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Y", - "Z" - ], - "rows": [ - { - "label": "X Offset [mm]", - "fields": [ - "grating.offx", - "grating.offy", - "grating.offz" - ] - }, - { - "label": "X Rotation [CCW, deg]", - "fields": [ - "grating.x_rot", - "grating.y_rot", - "grating.z_rot" - ] - } - ] - } - } - ] - }, - { - "name": "Main Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "grating.title", - "grating.position", - "grating.fmirr", - "grating.f_central", - "grating.f_phot_cent", - "grating.phot_cent", - "grating.r_lambda", - "grating.t_incidence", - "grating.t_reflection", - "grating.alpha" - ] - } - } - ] - }, - { - "name": "Surface Shape", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "grating.f_ext", - "grating.f_default", - "grating.ssour", - "grating.simag", - "grating.theta", - "grating.f_side", - "grating.rmirr", - "grating.param", - "grating.axmaj", - "grating.axmin", - "grating.ell_the", - "grating.f_convex", - "grating.fcyl", - "grating.cil_ang", - "grating.r_maj", - "grating.r_min", - "grating.f_torus" - ] - } - } - ] - }, - { - "name": "Grating", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "grating.f_ruling", - "grating.rulingDensity", - "grating.rulingDensityCenter", - "grating.rulingDensityPolynomial" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Entrance", - "Exit" - ], - "rows": [ - { - "label": "Entrance Slit Distance [mm]", - "fields": [ - "grating.holo_r1", - "grating.holo_r2" - ] - }, - { - "label": "Entrance Slit Incidence Angle [deg]", - "fields": [ - "grating.holo_del", - "grating.holo_gam" - ] - }, - { - "label": "Entrance Slit Rotation Angle [deg]", - "fields": [ - "grating.holo_rt1", - "grating.holo_rt2" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "grating.f_pw", - "grating.f_pw_c", - "grating.f_virtual", - "grating.holo_w", - "grating.azim_fan", - "grating.dist_fan", - "grating.coma_fac", - "grating.rul_a1", - "grating.rul_a2", - "grating.rul_a3", - "grating.rul_a4", - "grating.f_rul_abs" - ] - } - } - ] - }, - { - "name": "Diffraction", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "grating.order", - "grating.f_mono", - "grating.f_hunt", - "grating.hunt_h", - "grating.hunt_l", - "grating.blaze" - ] - } - } - ] - }, - { - "name": "Dimensions", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "grating.fhit_c", - "grating.fshape", - "grating.halfWidthX1", - "grating.halfWidthX2", - "grating.halfLengthY1", - "grating.halfLengthY2", - "grating.externalOutlineMajorAxis", - "grating.externalOutlineMinorAxis", - "grating.internalOutlineMajorAxis", - "grating.internalOutlineMinorAxis" - ] - } - } - ] - } - ] - } - } - ] - }, - "_NAME": "grating" - }, - { - "layout": "panel", - "config": { - "basic": [], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "lens.title", - "lens.position", - "lens.focal_x", - "lens.focal_z" - ] - } - } - ] - }, - "_NAME": "lens" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Misalignment", - "items": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "X", - "Y", - "Z" - ], - "rows": [ - { - "label": "X Offset [mm]", - "fields": [ - "mirror.offx", - "mirror.offy", - "mirror.offz" - ] - }, - { - "label": "X Rotation [CCW, deg]", - "fields": [ - "mirror.x_rot", - "mirror.y_rot", - "mirror.z_rot" - ] - } - ] - } - } - ] - }, - { - "name": "Main Parameters", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "mirror.title", - "mirror.position", - "mirror.fmirr", - "mirror.t_incidence", - "mirror.alpha" - ] - } - } - ] - }, - { - "name": "Surface Shape", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "mirror.f_ext", - "mirror.f_default", - "mirror.ssour", - "mirror.simag", - "mirror.theta", - "mirror.f_side", - "mirror.rmirr", - "mirror.param", - "mirror.axmaj", - "mirror.axmin", - "mirror.ell_the", - "mirror.f_convex", - "mirror.fcyl", - "mirror.cil_ang", - "mirror.r_maj", - "mirror.r_min", - "mirror.f_torus" - ] - } - } - ] - }, - { - "name": "Reflectivity", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "mirror.f_reflec", - "mirror.f_refl", - "mirror.reflectivityMinEnergy", - "mirror.reflectivityMaxEnergy", - "mirror.prereflStep", - "mirror.prereflElement", - "mirror.prereflDensity", - "mirror.f_thick" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Material", - "Density [g/m³]" - ], - "rows": [ - { - "label": "Material Substrate", - "fields": [ - "mirror.mlayerSubstrateMaterial", - "mirror.mlayerSubstrateDensity" - ] - }, - { - "label": "Material Even Sublayer", - "fields": [ - "mirror.mlayerEvenSublayerMaterial", - "mirror.mlayerEvenSublayerDensity" - ] - }, - { - "label": "Material Odd Sublayer", - "fields": [ - "mirror.mlayerOddSublayerMaterial", - "mirror.mlayerOddSublayerDensity" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "mirror.mlayerBilayerNumber", - "mirror.mlayerBilayerThickness", - "mirror.mlayerGammaRatio", - "mirror.mlayerEvenRoughness", - "mirror.mlayerOddRoughness" - ] - } - } - ] - }, - { - "name": "Dimensions", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "mirror.fhit_c", - "mirror.fshape", - "mirror.halfWidthX1", - "mirror.halfWidthX2", - "mirror.halfLengthY1", - "mirror.halfLengthY2", - "mirror.externalOutlineMajorAxis", - "mirror.externalOutlineMinorAxis", - "mirror.internalOutlineMajorAxis", - "mirror.internalOutlineMinorAxis" - ] - } - } - ] - } - ] - } - } - ] - }, - "_NAME": "mirror" - }, - { - "layout": "panel", - "config": { - "basic": [], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "obstacle.title", - "obstacle.position", - "obstacle.shape" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Size [mm]", - "fields": [ - "obstacle.horizontalSize", - "obstacle.verticalSize" - ] - }, - { - "label": "Horizontal Offset [mm]", - "fields": [ - "obstacle.horizontalOffset", - "obstacle.verticalOffset" - ] - } - ] - } - } - ] - }, - "_NAME": "obstacle" - }, - - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.name" - ] - } - } - ] - }, - "_NAME": "simulation" - }, - - { - "layout": "panel", - "config": { - "basic": [], - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "watch.title", - "watch.position" - ] - } - } - ] - }, - "_NAME": "watch" - }, - - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "zonePlate.title", - "zonePlate.position", - "zonePlate.zone_plate_type", - "zonePlate.width_coating", - "zonePlate.height", - "zonePlate.diameter", - "zonePlate.b_min", - "zonePlate.zone_plate_material", - "zonePlate.template_material", - "zonePlate.n_points", - "zonePlate.last_index" - ] - } + } + ] } ] - }, - "_NAME": "zonePlate" + } + } ] } diff --git a/sirepo/package_data/static/svg/react-svg/aperture.svg b/sirepo/package_data/static/svg/react-svg/aperture.svg new file mode 100755 index 0000000000..82eb2f8785 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/aperture.svg @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/crl.svg b/sirepo/package_data/static/svg/react-svg/crl.svg new file mode 100755 index 0000000000..533f160ef8 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/crl.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/crystal.svg b/sirepo/package_data/static/svg/react-svg/crystal.svg new file mode 100755 index 0000000000..5ede3f4462 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/crystal.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/ellipsoidMirror.svg b/sirepo/package_data/static/svg/react-svg/ellipsoidMirror.svg new file mode 100755 index 0000000000..adb67c170c --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/ellipsoidMirror.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/emptyElement.svg b/sirepo/package_data/static/svg/react-svg/emptyElement.svg new file mode 100644 index 0000000000..f059f665da --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/emptyElement.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/fiber.svg b/sirepo/package_data/static/svg/react-svg/fiber.svg new file mode 100755 index 0000000000..d3f1b76dff --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/fiber.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/grating.svg b/sirepo/package_data/static/svg/react-svg/grating.svg new file mode 100755 index 0000000000..bae43fba46 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/grating.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/lens.svg b/sirepo/package_data/static/svg/react-svg/lens.svg new file mode 100755 index 0000000000..629bae3e46 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/lens.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/mask.svg b/sirepo/package_data/static/svg/react-svg/mask.svg new file mode 100755 index 0000000000..b281a3081b --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/mask.svg @@ -0,0 +1,456 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/mirror.svg b/sirepo/package_data/static/svg/react-svg/mirror.svg new file mode 100755 index 0000000000..760f47b38c --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/mirror.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/obstacle.svg b/sirepo/package_data/static/svg/react-svg/obstacle.svg new file mode 100755 index 0000000000..a42891a81e --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/obstacle.svg @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/sample.svg b/sirepo/package_data/static/svg/react-svg/sample.svg new file mode 100755 index 0000000000..d991413e63 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/sample.svg @@ -0,0 +1,785 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/sphericalMirror.svg b/sirepo/package_data/static/svg/react-svg/sphericalMirror.svg new file mode 100755 index 0000000000..14fdf21042 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/sphericalMirror.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/toroidalMirror.svg b/sirepo/package_data/static/svg/react-svg/toroidalMirror.svg new file mode 100755 index 0000000000..335bf2354a --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/toroidalMirror.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/watch.svg b/sirepo/package_data/static/svg/react-svg/watch.svg new file mode 100755 index 0000000000..c46f91b302 --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/watch.svg @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/package_data/static/svg/react-svg/zonePlate.svg b/sirepo/package_data/static/svg/react-svg/zonePlate.svg new file mode 100755 index 0000000000..be0c7f751b --- /dev/null +++ b/sirepo/package_data/static/svg/react-svg/zonePlate.svg @@ -0,0 +1,1091 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sirepo/sim_data/shadow.py b/sirepo/sim_data/shadow.py index 2c0912bf64..a4c9bfc6c7 100644 --- a/sirepo/sim_data/shadow.py +++ b/sirepo/sim_data/shadow.py @@ -5,6 +5,7 @@ :license: http://www.apache.org/licenses/LICENSE-2.0.html """ from __future__ import absolute_import, division, print_function +from pykern.pkcollections import PKDict from pykern.pkdebug import pkdc, pkdlog, pkdp import sirepo.sim_data import scipy.constants @@ -21,6 +22,7 @@ def fixup_old_data(cls, data, qcall, **kwargs): ( "beamStatisticsReport", "bendingMagnet", + "histogramReport", "initialIntensityReport", "plotXYReport", "undulator", @@ -34,11 +36,34 @@ def fixup_old_data(cls, data, qcall, **kwargs): * float(dm.electronBeam.bener) / float(dm.bendingMagnet.r_magnet) ) + if isinstance(dm.beamline, list): + dm.beamline = PKDict( + elements=list(map(lambda i: PKDict( + model=i.type, + item=i + ), dm.beamline)) + ) + pkdp(dm) + if not "watchpointReports" in dm: + dm.watchpointReports = PKDict( + reports=[] + ) + n = [] for m in dm: - if cls.is_watchpoint(m): + if cls.is_watchpoint(m) and m != "watchpointReports": cls.update_model_defaults(dm[m], "watchpointReport") - for m in dm.beamline: + i = cls.watchpoint_id(m) + dm[m].id = i + dm.watchpointReports.reports.append(PKDict( + model="watchpointReport", + item=dm[m] + )) + n.append(m) + for i in n: + del dm[i] + for m in map(lambda i: i.item, dm.beamline.elements): cls.update_model_defaults(m, m.type) + pkdp(dm) cls._organize_example(data) @classmethod @@ -67,8 +92,8 @@ def _compute_job_fields(cls, data, r, compute_model): "undulatorBeam", "wiggler", ] - if r == "initialIntensityReport" and data["models"]["beamline"]: - res.append([data["models"]["beamline"][0]["position"]]) + if r == "initialIntensityReport" and data["models"]["beamline"] and data["models"]["beamline"]["elements"] and len(data["models"]["beamline"]["elements"]) > 0: + res.append([data["models"]["beamline"]["elements"][0]["item"]["position"]]) # TODO(pjm): only include items up to the current watchpoint if cls.is_watchpoint(r) or r == "beamStatisticsReport": res.append("beamline") diff --git a/sirepo/template/shadow.py b/sirepo/template/shadow.py index 2b9821fb5d..8b43116b7a 100644 --- a/sirepo/template/shadow.py +++ b/sirepo/template/shadow.py @@ -182,13 +182,20 @@ def post_execution_processing(success_exit, is_parallel, run_dir, **kwargs): def python_source_for_model(data, model, qcall, **kwargs): data.report = model if not model: - beamline = data.models.beamline + beamline = list(map(lambda i: i.item, data.models.beamline.elements)) watch_id = None + watch_index = None for b in beamline: if b.type == "watch": watch_id = b.id if watch_id: - data.report = "{}{}".format(_SIM_DATA.WATCHPOINT_REPORT, watch_id) + for i, w in enumerate(data.models.watchpointReports.reports): + if w.item.id == watch_id: + watch_index = i + if watch_index: + data.report = "{}{}".format(_SIM_DATA.WATCHPOINT_REPORT, watch_index) + else: + data.report = "plotXYReport" else: data.report = "plotXYReport" return """ @@ -288,7 +295,7 @@ def _generate_autotune_element(item): def _generate_beamline_optics(models, last_id=None, calc_beam_stats=False): - beamline = models.beamline + beamline = list(map(lambda i: i.item, models.beamline.elements)) res = "" prev_position = source_position = 0 last_element = False @@ -723,8 +730,9 @@ def _generate_parameters_file(data, run_dir=None, is_parallel=False): _scale_units(data) v = template_common.flatten_data(data.models, PKDict()) r = data.report - report_model = data.models[r] - beamline = data.models.beamline + + #report_model = data.models[r] + beamline = list(map(lambda i: i.item, data.models.beamline.elements)) v.shadowOutputFile = _SHADOW_OUTPUT_FILE if _has_zone_plate(beamline): v.zonePlateMethods = template_common.render_jinja(SIM_TYPE, v, "zone_plate.py") @@ -773,11 +781,13 @@ def _generate_parameters_file(data, run_dir=None, is_parallel=False): v.photonEnergy = v.bendingMagnet_ph1 return template_common.render_jinja(SIM_TYPE, v, "beam_statistics.py") elif _SIM_DATA.is_watchpoint(r): + di = _SIM_DATA.watchpoint_id(r) + rd = data.models.watchpointReports.reports[di] v.beamlineOptics = _generate_beamline_optics( - data.models, last_id=_SIM_DATA.watchpoint_id(r) + data.models, last_id=rd.item.id ) else: - v.distanceFromSource = report_model.distanceFromSource + v.distanceFromSource = data.models[r].distanceFromSource return template_common.render_jinja(SIM_TYPE, v) @@ -969,7 +979,7 @@ def _scale_units(data): for name in _MODEL_UNITS.unit_def: if name in data.models: _MODEL_UNITS.scale_to_native(name, data.models[name]) - for item in data.models.beamline: + for item in list(map(lambda i: i.item, data.models.beamline.elements)): if item.type in _MODEL_UNITS.unit_def: _MODEL_UNITS.scale_to_native(item.type, item) diff --git a/sirepo/template/template_common.py b/sirepo/template/template_common.py index dc53d6687a..00e11bd898 100644 --- a/sirepo/template/template_common.py +++ b/sirepo/template/template_common.py @@ -822,7 +822,9 @@ def validate_models(model_data, model_schema): enum_info, ) if "beamline" in model_data["models"]: - for m in model_data["models"]["beamline"]: + for m in model_data["models"]["beamline"]["elements"]: + if isinstance(m, PKDict): + m = m.item validate_model(m, model_schema["model"][m["type"]], enum_info) return enum_info From 6664bd9c2f59cf0d403ac1aacf151c49dcfe2381 Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 17 Mar 2023 01:23:02 +0000 Subject: [PATCH 11/68] wip basic beamline functionality --- react/src/layout/beamline.tsx | 65 ++++++++++++++++--- .../static/react-json/shadow-schema.json | 10 +++ 2 files changed, 67 insertions(+), 8 deletions(-) diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 573a408246..beae713e02 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -1,11 +1,13 @@ import React, { useContext } from "react"; import { FunctionComponent } from "react"; +import { Modal } from "react-bootstrap"; import { ModelsAccessor } from "../data/accessor"; import { Dependency } from "../data/dependency"; import { CFormStateWrapper } from "../data/wrapper"; import { FormModelState } from "../store/formState"; import { CRouteHelper } from "../utility/route"; import { SchemaLayout } from "../utility/schema"; +import { FormControllerElement } from "./form"; import { ArrayField } from "./input/array"; import { Layout, LayoutProps } from "./layout"; import { createLayouts } from "./layouts"; @@ -13,6 +15,7 @@ import { createLayouts } from "./layouts"; export type BeamlineElement = { items: SchemaLayout[], name: string, + model: string, icon: string } @@ -21,6 +24,17 @@ export type BeamlineConfig = { elements: BeamlineElement[] } +export function BeamlineItem(props: { name: string, iconSrc: string }) { + return ( +

+
+ +
+

{props.name}

+
+ ) +} + export class BeamlineLayout extends Layout { private elements: (BeamlineElement & {layouts: Layout[]})[]; @@ -40,18 +54,51 @@ export class BeamlineLayout extends Layout { let accessor = new ModelsAccessor(formStateWrapper, [beamlineDependency]); - let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; + let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency).value as ArrayField; let elementThumbnails = this.elements.map((e, i) => { return ( -
-
- -
-

{e.name}

-
+ ) }) + + console.log("elements", this.elements); + + let findBaseElementByModel = (model: string) => { + let r = this.elements.filter(e => e.model === model); + if(r.length > 1) { + throw new Error(`multiple beamline base elements found with model=${model}`); + } + return r[0]; + } + + console.log("beamlineValue", beamlineValue); + let beamlineComponents = beamlineValue.map((e, i) => { + let model = e.model; + let ele: FormModelState = e.item; + + let baseElement = findBaseElementByModel(model); + //let deps = baseElement.layouts.flatMap(l => l.getFormDependencies()); + let deps = []; + + /*let modal = ( + + { + baseElement.layouts.map(l => { + let Comp = l.component; + return + }) + } + + )*/ + // TODO: override form controller + return ( + + + + ) + }) + return ( <>
@@ -69,7 +116,9 @@ export class BeamlineLayout extends Layout {

- +
+ {beamlineComponents} +
) diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index 9e73381d2b..87a3cdbef3 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -4237,6 +4237,7 @@ "elements": [ { "name": "Aperture", + "model": "aperture", "icon": "aperture.svg", "items": [ { @@ -4278,6 +4279,7 @@ }, { "name": "CRL", + "model": "crl", "icon": "crl.svg", "items": [ { @@ -4308,6 +4310,7 @@ }, { "name": "Crystal", + "model": "crystal", "icon": "crystal.svg", "items": [ { @@ -4520,6 +4523,7 @@ }, { "name": "Empty Element", + "model": "emptyElement", "icon": "emptyElement.svg", "items": [ { @@ -4536,6 +4540,7 @@ }, { "name": "Grating", + "model": "grating", "icon": "grating.svg", "items": [ { @@ -4740,6 +4745,7 @@ }, { "name": "Lens", + "model": "lens", "icon": "lens.svg", "items": [ { @@ -4757,6 +4763,7 @@ }, { "name": "Mirror", + "model": "mirror", "icon": "mirror.svg", "items": [ { @@ -4935,6 +4942,7 @@ }, { "name": "Obstacle", + "model": "obstacle", "icon": "obstacle.svg", "items": [ { @@ -4976,6 +4984,7 @@ }, { "name": "Watch", + "model": "watch", "icon": "watch.svg", "items": [ { @@ -4991,6 +5000,7 @@ }, { "name": "Zone Plate", + "model": "zonePlate", "icon": "zonePlate.svg", "items": [ { From 4f21beb46fc6f3847cc05568dda587957fd82657 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 21 Mar 2023 00:08:13 +0000 Subject: [PATCH 12/68] wip add edit functionality to beamline --- react/src/component/reusable/form.tsx | 25 +- .../reusable/{panel.js => panel.tsx} | 6 +- react/src/component/simulation.tsx | 5 +- react/src/data/formController.ts | 23 +- react/src/data/wrapper.ts | 86 ++++--- react/src/layout/beamline.tsx | 219 +++++++++++++++--- react/src/layout/layouts.ts | 2 +- react/src/layout/navbar.tsx | 15 +- react/src/layout/panel.tsx | 6 +- .../static/react-json/shadow-schema.json | 8 +- sirepo/sim_data/shadow.py | 2 - 11 files changed, 298 insertions(+), 99 deletions(-) rename react/src/component/reusable/{panel.js => panel.tsx} (92%) diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 720ebce52f..16ba2edf89 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -13,10 +13,13 @@ import { formActions, formSelectors } from "../../store/formState"; -import { formStateFromModel } from "../../data/formController"; +import { FormController, formStateFromModel } from "../../data/formController"; import { useStore } from "react-redux"; -import { CModelsWrapper, CFormStateWrapper, FormStateWrapper } from "../../data/wrapper"; -import { CSchema } from "../../data/appwrapper"; +import { CModelsWrapper, CFormStateWrapper, FormStateWrapper, ModelsWrapper, AbstractModelsWrapper } from "../../data/wrapper"; +import { CSchema, CSimulationInfoPromise } from "../../data/appwrapper"; +import { SimulationInfo } from "../simulation"; +import { Schema } from "../../utility/schema"; +import { AnyAction, Store } from "redux"; export function FormField(props) { let { label, tooltip, ...passedProps } = props; @@ -43,6 +46,18 @@ export function EditorForm(props) { ); } +export function formActionFunctions(formController: FormController, store: Store, simulationInfoPromise: Promise, schema: Schema, modelsWrapper: ModelsWrapper): { cancel: () => void, submit: () => void } { + return { + cancel: () => formController.cancelChanges(store.getState()), + submit: () => { + formController.saveToModels(store.getState()); + simulationInfoPromise.then(simulationInfo => { + modelsWrapper.saveToServer(simulationInfo, Object.keys(schema.models), store.getState()) + }) + } + } +} + export function FormStateInitializer(props) { let [hasInit, updateHasInit] = useState(undefined); @@ -56,7 +71,7 @@ export function FormStateInitializer(props) { formSelectors }) - let modelNames = models.getModelNames(store.getState()); + let modelNames = (models as ModelsWrapper).getModelNames(store.getState()); useEffect(() => { let state = store.getState(); @@ -73,7 +88,7 @@ export function FormStateInitializer(props) { if(!modelSchema) { throw new Error(`could not get schema for model=${modelName}`); } - formState.updateModel(modelName, formStateFromModel(value, modelSchema, schema)); + formState.updateModel(modelName, formStateFromModel(value, modelSchema, schema), store.getState()); }); updateHasInit(true); diff --git a/react/src/component/reusable/panel.js b/react/src/component/reusable/panel.tsx similarity index 92% rename from react/src/component/reusable/panel.js rename to react/src/component/reusable/panel.tsx index 528334fce2..62308651a9 100644 --- a/react/src/component/reusable/panel.js +++ b/react/src/component/reusable/panel.tsx @@ -4,13 +4,17 @@ import { Button, Modal } from "react-bootstrap"; -import React, { useState, Fragment } from "react"; +import React, { useState, Fragment, useContext } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; import { EditorForm } from "./form"; import { v4 as uuidv4 } from 'uuid'; import { CPanelController } from "../../data/panel" import { PanelController } from "../../data/panel"; +import { CFormController } from "../../data/formController"; +import { useStore } from "react-redux"; +import { CSchema, CSimulationInfoPromise } from "../../data/appwrapper"; +import { CModelsWrapper, ModelsWrapper } from "../../data/wrapper"; export function Panel(props) { let { title, buttons, panelBodyShown } = props; diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 1c6433c1d6..09ceb82a08 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -30,6 +30,7 @@ import * as Icon from "@fortawesome/free-solid-svg-icons"; import { useSetup } from "../hook/setup"; import { Portal } from "./reusable/portal"; import { downloadAs, getAttachmentFileName } from "../utility/download"; +import { useStore } from "react-redux"; export type SimulationInfoRaw = { models: ModelStates, @@ -48,6 +49,7 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let [hasInit, updateHasInit] = useState(false); let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); + let store = useStore(); let modelsWrapper = new ModelsWrapper({ modelActions, @@ -63,9 +65,10 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri })).then(async (resp) => { let simulationInfo = await resp.json(); let models = simulationInfo['models'] as ModelState[]; + console.log("models", models); for(let [modelName, model] of Object.entries(models)) { - modelsWrapper.updateModel(modelName, model); + modelsWrapper.updateModel(modelName, model, store.getState()); } resolve({...simulationInfo, simulationId}); diff --git a/react/src/data/formController.ts b/react/src/data/formController.ts index f19ced08c5..1041fac3e9 100644 --- a/react/src/data/formController.ts +++ b/react/src/data/formController.ts @@ -18,13 +18,18 @@ export let formStateFromModel = (model: ModelState, modelSchema: SchemaModel, sc throw new Error(`while converting model to form state, model was undefined; schema=${JSON.stringify(modelSchema)}`); } // TODO: should this be mapping from schema or from the model being mapped? - return mapProperties(modelSchema, (fieldName, { type, typeName }) => { + return mapProperties(modelSchema, (fieldName, { type }) => { if(!(fieldName in model)) { - throw new Error(`model=${JSON.stringify(model)} was missing field=${fieldName}`) + if(modelSchema[fieldName].defaultValue !== undefined) { + model[fieldName] = modelSchema[fieldName].defaultValue; + } else { + throw new Error(`model=${JSON.stringify(model)} was missing field=${fieldName}`) + } } - if(typeName === "Array") { - let v: {item: ModelState, model: string}[] = model[fieldName] as any[] || []; + let mv = model[fieldName]; + if(mv.constructor && mv.constructor.name == "Array") { + let v: {item: ModelState, model: string}[] = mv as any[] || []; return v.map(i => { return { item: formStateFromModel(i.item, schema.models[i.model], schema), @@ -66,7 +71,7 @@ export class FormController { this.modelStatesAccessor = new ModelsAccessor(modelsWrapper, dependencies) } - saveToModels = () => { + saveToModels = (state: any) => { let f = this.formStatesAccessor.getValues(); this.formStatesAccessor.getModelNames().map(mn => { return { @@ -86,11 +91,11 @@ export class FormController { Object.assign(m, modelChanges.changes); console.log("submitting value ", m, " to ", modelChanges.modelName); - this.modelsWrapper.updateModel(modelChanges.modelName, m); + this.modelsWrapper.updateModel(modelChanges.modelName, m, state); // this should make sure that if any part of the reducers are inconsistent / cause mutations // then the form state should remain consistent with saved model copy // TODO: this line has been changed with recent update, evaluate - this.formStatesWrapper.updateModel(modelChanges.modelName, formStateFromModel(m, this.schema.models[modelChanges.modelName], this.schema)) + this.formStatesWrapper.updateModel(modelChanges.modelName, formStateFromModel(m, this.schema.models[modelChanges.modelName], this.schema), state) }) } @@ -106,11 +111,11 @@ export class FormController { return this.dependencies; } - cancelChanges = () => { + cancelChanges = (state: any) => { this.formStatesAccessor.modelNames.map(modelName => { return this.formStatesWrapper.updateModel(modelName, formStateFromModel( this.modelStatesAccessor.getModelValue(modelName), - this.schema.models[modelName], this.schema)); + this.schema.models[modelName], this.schema), state); }); } diff --git a/react/src/data/wrapper.ts b/react/src/data/wrapper.ts index 2211d46c3d..99fc33fc84 100644 --- a/react/src/data/wrapper.ts +++ b/react/src/data/wrapper.ts @@ -1,50 +1,68 @@ import React, { Dispatch } from "react"; import { useDispatch, useSelector } from "react-redux"; import { AnyAction } from "redux"; +import { ArrayModelElement } from "../layout/input/array"; import { FormActions, FormFieldState, FormModelState, FormSelectors } from "../store/formState"; import { ModelActions, ModelSelectors, ModelState } from "../store/models"; export abstract class AbstractModelsWrapper { abstract getModel(modelName: string, state: any): M; abstract hookModel(modelName: string): M; - abstract updateModel(modelName: string, value: M): void; + abstract updateModel(modelName: string, value: M, state: any): void; abstract getFieldFromModel(fieldName: string, model: M): F; abstract setFieldInModel(fieldName: string, model: M, value: F): M; getArraySubField = (fieldName: string, index: number, subFieldName: string, model: M): F => { + return this.getFieldFromModel(subFieldName, this.getArrayFieldAtIndex(fieldName, index, model).item); + } + + setArraySubField = (fieldName: string, index: number, subFieldName: string, model: M, value: F): M => { + let af = this.getArrayFieldAtIndex(fieldName, index, model); + let nm = this.setFieldInModel(subFieldName, af.item, value); + return this.setArrayFieldAtIndex(fieldName, index, model, { + item: nm, + model: af.model + }); + } + + getArrayFieldAtIndex = (fieldName: string, index: number, model: M): ArrayModelElement => { let fieldState = this.getFieldFromModel(fieldName, model); let len = this.getArrayFieldLength(fieldState); if(index >= len) { throw new Error(`index=${index} of out bounds=${len}`); } - return this.getFieldFromModel(subFieldName, fieldState[index]); + return fieldState[index]; } - setArraySubField = (fieldName: string, index: number, subFieldName: string, model: M, value: F) => { + setArrayFieldAtIndex = (fieldName: string, index: number, model: M, value: ArrayModelElement): M => { let fieldState = this.getFieldFromModel(fieldName, model); let len = this.getArrayFieldLength(fieldState); if(index >= len) { throw new Error(`index=${index} of out bounds=${len}`); } - let subModel = fieldState[index]; - this.setFieldInModel(subFieldName, subModel, value); + // TODO: cant change types of model + let nv = [...(fieldState as any)]; + console.log("value", value); + nv[index] = value; + console.log("nv", nv); + return this.setFieldInModel(fieldName, model, nv as F); } getArrayFieldLength = (field: F): number => { - return (field as any[] || []).length; + return ((field as any[]) || []).length; } updateField = (fieldName: string, modelName: string, state: any, value: F): void => { let model = this.getModel(modelName, state); model = this.setFieldInModel(fieldName, model, value); - this.updateModel(modelName, model); + this.updateModel(modelName, model, state); } } -export const CFormStateWrapper = React.createContext(undefined); -export const CModelsWrapper = React.createContext(undefined); +export const CFormStateWrapper = React.createContext>>(undefined); +export const CModelsWrapper = React.createContext>(undefined); export function getModelValues(modelNames: string[], modelsWrapper: AbstractModelsWrapper, state: any): {[modelName: string]: M} { return Object.fromEntries(modelNames.map(mn => [mn, modelsWrapper.getModel(mn, state)])); @@ -67,7 +85,7 @@ export class FormStateWrapper extends AbstractModelsWrapper { + override updateModel = (modelName: string, value: any, state: any) => { //console.log("dispatching update form to ", modelName, " changing to value ", value); this.dispatch(this.formActions.updateFormState({ name: modelName, @@ -120,7 +138,7 @@ export class ModelsWrapper extends AbstractModelsWrapper { return this.modelSelectors.selectModelNames()(state); } - updateModel = (modelName: string, value: ModelState) => { + updateModel = (modelName: string, value: ModelState, state: any) => { //console.log("dispatching update to ", modelName, " changing to value ", value); this.dispatch(this.modelActions.updateModel({ name: modelName, @@ -167,41 +185,47 @@ export class ModelsWrapper extends AbstractModelsWrapper { } -/*export type ModelAliases = { - [key: string]: string +export type ModelHandle = { + getModel(modelName: string, state: any): M, + hookModel(modelName: string): M, + updateModel(modelName: string, value: M, state: any): void +} + +/** + * Fake -> real + */ +export type ModelAliases = { + [fake: string]: { + handle: ModelHandle, + realSchemaName: string + } } export class ModelsWrapperWithAliases extends AbstractModelsWrapper { - private reverseAliases: ModelAliases = undefined; - constructor(private parent: AbstractModelsWrapper, private aliases: ModelAliases) { + constructor(private parent: AbstractModelsWrapper, private aliases: ModelAliases) { super(); - this.reverseAliases = Object.fromEntries(Object.entries(this.aliases).map(([name, value]) => [value, name])); - } - private getAliasedModelName = (mn: string): string => { - if(mn in this.aliases) { - return this.aliases[mn]; - } - return mn; + this['getModelNames'] = parent['getModelNames'] + this['saveToServer'] = parent['saveToServer'] } - private getInverseAliasedModelName = (mn: string): string => { - if(mn in this.reverseAliases) { - return this.reverseAliases[mn]; + private getAliasedHandle(modelName: string): ModelHandle | undefined { + if(modelName in this.aliases) { + return this.aliases[modelName].handle; } - return mn; + return undefined; } getModel(modelName: string, state: any): M { - return this.parent.getModel(this.getAliasedModelName(modelName), state); + return (this.getAliasedHandle(modelName) || this.parent).getModel(modelName, state); } hookModel(modelName: string): M { - return this.parent.hookModel(this.getAliasedModelName(modelName)); + return (this.getAliasedHandle(modelName) || this.parent).hookModel(modelName); } - updateModel(modelName: string, value: M): void { - return this.parent.updateModel(this.getAliasedModelName(modelName), value); + updateModel(modelName: string, value: M, state: any): void { + return (this.getAliasedHandle(modelName) || this.parent).updateModel(modelName, value, state); } getFieldFromModel(fieldName: string, model: M): F { @@ -211,7 +235,7 @@ export class ModelsWrapperWithAliases extends AbstractModelsWrapper setFieldInModel(fieldName: string, model: M, value: F): M { return this.parent.setFieldInModel(fieldName, model, value); } -}*/ +} diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index beae713e02..d8d1cab8c7 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -1,14 +1,19 @@ -import React, { useContext } from "react"; +import React, { useContext, useState } from "react"; import { FunctionComponent } from "react"; -import { Modal } from "react-bootstrap"; +import { Container, Modal } from "react-bootstrap"; +import { useStore } from "react-redux"; +import { formActionFunctions } from "../component/reusable/form"; +import { ViewPanelActionButtons } from "../component/reusable/panel"; import { ModelsAccessor } from "../data/accessor"; +import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { Dependency } from "../data/dependency"; -import { CFormStateWrapper } from "../data/wrapper"; -import { FormModelState } from "../store/formState"; +import { CFormController, formStateFromModel } from "../data/formController"; +import { AbstractModelsWrapper, CFormStateWrapper, CModelsWrapper, ModelAliases, ModelHandle, ModelsWrapper, ModelsWrapperWithAliases } from "../data/wrapper"; +import { FormFieldState, FormModelState } from "../store/formState"; import { CRouteHelper } from "../utility/route"; -import { SchemaLayout } from "../utility/schema"; +import { Schema, SchemaLayout } from "../utility/schema"; import { FormControllerElement } from "./form"; -import { ArrayField } from "./input/array"; +import { ArrayField, ArrayModelElement } from "./input/array"; import { Layout, LayoutProps } from "./layout"; import { createLayouts } from "./layouts"; @@ -24,9 +29,9 @@ export type BeamlineConfig = { elements: BeamlineElement[] } -export function BeamlineItem(props: { name: string, iconSrc: string }) { +export function BeamlineThumbnail(props: { name: string, iconSrc: string, onClick?: () => void }) { return ( -
+
@@ -35,6 +40,52 @@ export function BeamlineItem(props: { name: string, iconSrc: string }) { ) } +export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: Layout[] }, onClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { + let { baseElement, onClick, modalShown, onHideModal } = props; + + let routeHelper = useContext(CRouteHelper); + let formController = useContext(CFormController); + let store = useStore(); + let simulationInfoPromise = useContext(CSimulationInfoPromise); + let modelsWrapper = useContext(CModelsWrapper); + let schema = useContext(CSchema); + + // TODO: override form controller + //console.log("ele", ele); + //console.log("id", id); + console.log("modalShown", modalShown); + + let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); + + let isDirty = formController.isFormStateDirty(); + let isValid = formController.isFormStateValid(); + let actionButtons = + return ( + <> +
+ +
+ { + //_cancel(); + onHideModal(); + }}> + + {baseElement.name} + + + { + baseElement.layouts.map((l, i) => { + let Comp = l.component; + return + }) + } + {isDirty && actionButtons} + + + + ) +} + export class BeamlineLayout extends Layout { private elements: (BeamlineElement & {layouts: Layout[]})[]; @@ -48,21 +99,53 @@ export class BeamlineLayout extends Layout { } component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { + console.log("RENDER"); let routeHelper = useContext(CRouteHelper); let formStateWrapper = useContext(CFormStateWrapper); + let modelsWrapper = useContext(CModelsWrapper); + let formController = useContext(CFormController); + let store = useStore(); + let simulationInfoPromise = useContext(CSimulationInfoPromise); + let schema = useContext(CSchema); + let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); + let [shownModal, updateShownModal] = useState(undefined); + console.log("shownModal", shownModal); + let accessor = new ModelsAccessor(formStateWrapper, [beamlineDependency]); - let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency).value as ArrayField; + let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; + + let addBeamlineElement = (element: BeamlineElement) => { + let ms = schema.models[element.model]; + // TODO: use generic methods + let prev: FormModelState | undefined = beamlineValue.length > 0 ? beamlineValue[beamlineValue.length - 1].item : undefined + let nextPosition: number = prev ? prev.position.value + 5 : 0; + let nextId: number = prev ? prev.id.value + 1 : 1; + let mv = formStateFromModel({ + id: nextId, + position: nextPosition, + type: element.model + }, ms, schema); + let bv = [...beamlineValue]; + bv.push({ + item: mv, + model: element.model + }); + let m = formStateWrapper.getModel(beamlineDependency.modelName, store.getState()); + m = formStateWrapper.setFieldInModel(beamlineDependency.fieldName, m, bv as any as FormFieldState); + formStateWrapper.updateModel(beamlineDependency.modelName, m, store.getState()); + console.log("ADD ELEMENT"); + } let elementThumbnails = this.elements.map((e, i) => { return ( - + addBeamlineElement(e)} key={i} name={e.name} iconSrc={routeHelper.globalRoute("svg", { fileName: e.icon })}/> ) }) - console.log("elements", this.elements); + //console.log("elements", this.elements); let findBaseElementByModel = (model: string) => { let r = this.elements.filter(e => e.model === model); @@ -72,33 +155,41 @@ export class BeamlineLayout extends Layout { return r[0]; } - console.log("beamlineValue", beamlineValue); + //console.log("beamlineValue", beamlineValue); let beamlineComponents = beamlineValue.map((e, i) => { let model = e.model; let ele: FormModelState = e.item; - + let id = ele.id.value; let baseElement = findBaseElementByModel(model); - //let deps = baseElement.layouts.flatMap(l => l.getFormDependencies()); - let deps = []; - - /*let modal = ( - - { - baseElement.layouts.map(l => { - let Comp = l.component; - return - }) - } - - )*/ - // TODO: override form controller + let deps = baseElement.layouts.flatMap(l => l.getFormDependencies()); + let aliases: FormControllerAliases = [ + { + real: { + modelName: beamlineDependency.modelName, + fieldName: beamlineDependency.fieldName, + index: i + }, + fake: model, + realSchemaName: model + } + ]; return ( - - - + + + + updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> + + + ) }) + let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); + + let isDirty = formController.isFormStateDirty(); + let isValid = formController.isFormStateValid(); + let actionButtons = + return ( <>
@@ -119,8 +210,76 @@ export class BeamlineLayout extends Layout {
{beamlineComponents}
+
+ {isDirty && actionButtons} +
) } } + +export function arrayPositionHandle(modelsWrapper: AbstractModelsWrapper, realArrayDep: Dependency, arrayIndex: number): ModelHandle { + let handle: ModelHandle = { + updateModel: (modelName: string, value: M, state: any) => { + let m = modelsWrapper.getModel(realArrayDep.modelName, state); + let nm = modelsWrapper.setArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m, { + model: modelName, + item: value + }); + modelsWrapper.updateModel(realArrayDep.modelName, nm, state); + }, + getModel: (modelName: string, state: any): M => { + let m = modelsWrapper.getModel(realArrayDep.modelName, state); + return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; + }, + hookModel: (modelName: string): M => { + let m = modelsWrapper.hookModel(realArrayDep.modelName); + return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; + } + } + return handle; +} + +export type FormControllerAliases = { real: { modelName: string, fieldName: string, index: number }, fake: string, realSchemaName: string }[] +export function AliasedFormControllerWrapper(props: { aliases: FormControllerAliases, children?: React.ReactNode }) { + let { aliases } = props; + + let schema = useContext(CSchema); + let modelsWrapper = useContext(CModelsWrapper); + let formStateWrapper = useContext(CFormStateWrapper); + + let nSchema: Schema = {...schema}; + + + for(let alias of aliases) { + nSchema.models[alias.fake] = nSchema.models[alias.realSchemaName]; + } + + function aliasesForWrapper(wrapper: AbstractModelsWrapper, aliases: FormControllerAliases): ModelAliases { + return Object.fromEntries( + aliases.map(alias => { + return [ + alias.fake, + { + handle: arrayPositionHandle(wrapper, new Dependency(`${alias.real.modelName}.${alias.real.fieldName}`), alias.real.index), + realSchemaName: alias.realSchemaName + } + ] + }) + ); + } + + let nModelsWrapper = new ModelsWrapperWithAliases(modelsWrapper, aliasesForWrapper(modelsWrapper, aliases)); + let nFormStateWrapper = new ModelsWrapperWithAliases(formStateWrapper, aliasesForWrapper(formStateWrapper, aliases)); + + return ( + + + + {props.children} + + + + ) +} diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index 59ec8f2be6..2bbde82d7f 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -44,7 +44,7 @@ class LayoutWrapper { vStack: VerticalStackLayout, waterfall: WaterfallLayout, beamlineWatchpointReports: BeamlineWatchpointReports, - beamline: BeamlineLayout + beamline: LayoutWithFormController(BeamlineLayout) } constructor () { diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index 2aa991baf9..5ec3f6da82 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -11,11 +11,12 @@ import * as Icon from "@fortawesome/free-solid-svg-icons"; import { CRelativeRouterHelper, RelativeRouteHelper } from "../utility/route"; import React from "react"; import { CFormController } from "../data/formController"; -import { CModelsWrapper } from "../data/wrapper"; +import { CModelsWrapper, ModelsWrapper } from "../data/wrapper"; import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; import { Portal } from "../component/reusable/portal"; +import { formActionFunctions } from "../component/reusable/form"; export type NavBarModalButtonConfig = { modal: { @@ -57,17 +58,7 @@ export class NavBarModalButton extends Layout { let store = useStore(); - let _cancel = () => { - updateModalShown(false); - formController.cancelChanges(); - } - - let _submit = () => { - formController.saveToModels(); - simulationInfoPromise.then(simulationInfo => { - modelsWrapper.saveToServer(simulationInfo, Object.keys(schema.models), store.getState()); - }) - } + let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); let children = this.children.map((child, idx) => { let LayoutElement = child.component; diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 1639b769fe..f178efde1d 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -6,7 +6,7 @@ import { EditorPanel } from "../component/reusable/panel"; import "./panel.scss"; import React from "react"; import { CFormController } from "../data/formController"; -import { CModelsWrapper } from "../data/wrapper"; +import { CModelsWrapper, ModelsWrapper } from "../data/wrapper"; import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; @@ -50,9 +50,9 @@ export class PanelLayout extends Layout { let modalChildren = (!!this.advanced) ? mapLayoutsToComponents(this.advanced) : undefined; let submit = () => { - formController.saveToModels(); + formController.saveToModels(store.getState()); simulationInfoPromise.then(simulationInfo => { - modelsWrapper.saveToServer(simulationInfo, Object.keys(schema.models), store.getState()); + (modelsWrapper as ModelsWrapper).saveToServer(simulationInfo, Object.keys(schema.models), store.getState()); }) } diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index 87a3cdbef3..bfb7f19e8b 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -4446,7 +4446,7 @@ "layout": "fieldList", "config": { "fields": [ - "braggMaterial" + "crystal.braggMaterial" ] } } @@ -4469,9 +4469,9 @@ "layout": "fieldList", "config": { "fields": [ - "braggMillerH", - "braggMillerK", - "braggMillerL" + "crystal.braggMillerH", + "crystal.braggMillerK", + "crystal.braggMillerL" ] } } diff --git a/sirepo/sim_data/shadow.py b/sirepo/sim_data/shadow.py index a4c9bfc6c7..0cac005fc3 100644 --- a/sirepo/sim_data/shadow.py +++ b/sirepo/sim_data/shadow.py @@ -43,7 +43,6 @@ def fixup_old_data(cls, data, qcall, **kwargs): item=i ), dm.beamline)) ) - pkdp(dm) if not "watchpointReports" in dm: dm.watchpointReports = PKDict( reports=[] @@ -63,7 +62,6 @@ def fixup_old_data(cls, data, qcall, **kwargs): del dm[i] for m in map(lambda i: i.item, dm.beamline.elements): cls.update_model_defaults(m, m.type) - pkdp(dm) cls._organize_example(data) @classmethod From 7a3adcf9962e1d88088fdc31b82c4644713fc0db Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 22 Mar 2023 22:11:33 +0000 Subject: [PATCH 13/68] wip add watchpoint reports --- react/src/data/wrapper.ts | 6 +- react/src/layout/beamline.tsx | 67 +------- react/src/layout/form.tsx | 68 +++++++- .../shadow/beamlineWatchpointReports.tsx | 153 +++++++++++++++++- react/utility/convertschema.ts | 2 +- .../static/react-json/shadow-schema.json | 7 + sirepo/pkcli/shadow.py | 10 +- sirepo/sim_data/shadow.py | 58 +++++++ sirepo/template/shadow.py | 1 + 9 files changed, 298 insertions(+), 74 deletions(-) diff --git a/react/src/data/wrapper.ts b/react/src/data/wrapper.ts index 99fc33fc84..eca518937b 100644 --- a/react/src/data/wrapper.ts +++ b/react/src/data/wrapper.ts @@ -29,7 +29,8 @@ export abstract class AbstractModelsWrapper { let fieldState = this.getFieldFromModel(fieldName, model); let len = this.getArrayFieldLength(fieldState); if(index >= len) { - throw new Error(`index=${index} of out bounds=${len}`); + //throw new Error(`index=${index} of out bounds=${len}`); + return undefined; } return fieldState[index]; @@ -39,7 +40,8 @@ export abstract class AbstractModelsWrapper { let fieldState = this.getFieldFromModel(fieldName, model); let len = this.getArrayFieldLength(fieldState); if(index >= len) { - throw new Error(`index=${index} of out bounds=${len}`); + //throw new Error(`index=${index} of out bounds=${len}`); + return undefined; } // TODO: cant change types of model diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index d8d1cab8c7..8a92e69a21 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -12,7 +12,7 @@ import { AbstractModelsWrapper, CFormStateWrapper, CModelsWrapper, ModelAliases, import { FormFieldState, FormModelState } from "../store/formState"; import { CRouteHelper } from "../utility/route"; import { Schema, SchemaLayout } from "../utility/schema"; -import { FormControllerElement } from "./form"; +import { AliasedFormControllerWrapper, FormControllerAliases, FormControllerElement } from "./form"; import { ArrayField, ArrayModelElement } from "./input/array"; import { Layout, LayoutProps } from "./layout"; import { createLayouts } from "./layouts"; @@ -128,6 +128,7 @@ export class BeamlineLayout extends Layout { position: nextPosition, type: element.model }, ms, schema); + console.log("new beamline element mv", mv); let bv = [...beamlineValue]; bv.push({ item: mv, @@ -219,67 +220,3 @@ export class BeamlineLayout extends Layout { } } -export function arrayPositionHandle(modelsWrapper: AbstractModelsWrapper, realArrayDep: Dependency, arrayIndex: number): ModelHandle { - let handle: ModelHandle = { - updateModel: (modelName: string, value: M, state: any) => { - let m = modelsWrapper.getModel(realArrayDep.modelName, state); - let nm = modelsWrapper.setArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m, { - model: modelName, - item: value - }); - modelsWrapper.updateModel(realArrayDep.modelName, nm, state); - }, - getModel: (modelName: string, state: any): M => { - let m = modelsWrapper.getModel(realArrayDep.modelName, state); - return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; - }, - hookModel: (modelName: string): M => { - let m = modelsWrapper.hookModel(realArrayDep.modelName); - return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; - } - } - return handle; -} - -export type FormControllerAliases = { real: { modelName: string, fieldName: string, index: number }, fake: string, realSchemaName: string }[] -export function AliasedFormControllerWrapper(props: { aliases: FormControllerAliases, children?: React.ReactNode }) { - let { aliases } = props; - - let schema = useContext(CSchema); - let modelsWrapper = useContext(CModelsWrapper); - let formStateWrapper = useContext(CFormStateWrapper); - - let nSchema: Schema = {...schema}; - - - for(let alias of aliases) { - nSchema.models[alias.fake] = nSchema.models[alias.realSchemaName]; - } - - function aliasesForWrapper(wrapper: AbstractModelsWrapper, aliases: FormControllerAliases): ModelAliases { - return Object.fromEntries( - aliases.map(alias => { - return [ - alias.fake, - { - handle: arrayPositionHandle(wrapper, new Dependency(`${alias.real.modelName}.${alias.real.fieldName}`), alias.real.index), - realSchemaName: alias.realSchemaName - } - ] - }) - ); - } - - let nModelsWrapper = new ModelsWrapperWithAliases(modelsWrapper, aliasesForWrapper(modelsWrapper, aliases)); - let nFormStateWrapper = new ModelsWrapperWithAliases(formStateWrapper, aliasesForWrapper(formStateWrapper, aliases)); - - return ( - - - - {props.children} - - - - ) -} diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index 45393e1ff6..1bd93c321f 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -10,10 +10,11 @@ import { Dependency } from "../data/dependency"; import { FieldInput, LabeledFieldInput } from "../component/reusable/input"; import { CFormController, fieldStateFromValue, FormController } from "../data/formController"; import { useShown } from "../hook/shown"; -import { CModelsWrapper, CFormStateWrapper } from "../data/wrapper"; +import { CModelsWrapper, CFormStateWrapper, ModelsWrapperWithAliases, AbstractModelsWrapper, ModelAliases, ModelHandle } from "../data/wrapper"; import { useStore } from "react-redux"; import { CSchema } from "../data/appwrapper"; import { ValueSelectors } from "../utility/string"; +import { Schema } from "../utility/schema"; export function FormControllerElement(props: {children?: React.ReactNode, dependencies: Dependency[]}) { let formState = useContext(CFormStateWrapper); @@ -180,3 +181,68 @@ export class FieldListLayout extends Layout { } } + +export function arrayPositionHandle(modelsWrapper: AbstractModelsWrapper, realArrayDep: Dependency, arrayIndex: number): ModelHandle { + let handle: ModelHandle = { + updateModel: (modelName: string, value: M, state: any) => { + let m = modelsWrapper.getModel(realArrayDep.modelName, state); + let nm = modelsWrapper.setArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m, { + model: modelName, + item: value + }); + modelsWrapper.updateModel(realArrayDep.modelName, nm, state); + }, + getModel: (modelName: string, state: any): M => { + let m = modelsWrapper.getModel(realArrayDep.modelName, state); + return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; + }, + hookModel: (modelName: string): M => { + let m = modelsWrapper.hookModel(realArrayDep.modelName); + return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; + } + } + return handle; +} + +export type FormControllerAliases = { real: { modelName: string, fieldName: string, index: number }, fake: string, realSchemaName: string }[] +export function AliasedFormControllerWrapper(props: { aliases: FormControllerAliases, children?: React.ReactNode }) { + let { aliases } = props; + + let schema = useContext(CSchema); + let modelsWrapper = useContext(CModelsWrapper); + let formStateWrapper = useContext(CFormStateWrapper); + + let nSchema: Schema = {...schema}; + + + for(let alias of aliases) { + nSchema.models[alias.fake] = nSchema.models[alias.realSchemaName]; + } + + function aliasesForWrapper(wrapper: AbstractModelsWrapper, aliases: FormControllerAliases): ModelAliases { + return Object.fromEntries( + aliases.map(alias => { + return [ + alias.fake, + { + handle: arrayPositionHandle(wrapper, new Dependency(`${alias.real.modelName}.${alias.real.fieldName}`), alias.real.index), + realSchemaName: alias.realSchemaName + } + ] + }) + ); + } + + let nModelsWrapper = new ModelsWrapperWithAliases(modelsWrapper, aliasesForWrapper(modelsWrapper, aliases)); + let nFormStateWrapper = new ModelsWrapperWithAliases(formStateWrapper, aliasesForWrapper(formStateWrapper, aliases)); + + return ( + + + + {props.children} + + + + ) +} diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index 29b5d78231..2ddc14e901 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -3,19 +3,164 @@ import { FunctionComponent, useContext } from "react"; import { ModelsAccessor } from "../../data/accessor"; import { Dependency } from "../../data/dependency"; import { CFormStateWrapper } from "../../data/wrapper"; +import { FormModelState } from "../../store/formState"; import { SchemaLayout } from "../../utility/schema"; +import { AliasedFormControllerWrapper, FormControllerAliases } from "../form"; +import { ArrayField } from "../input/array"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; -export class BeamlineWatchpointReports extends Layout<{}, {}> { +export type BeamlineWatchpointReportsConfig = { + beamlineDependency: string, + watchpointReportsDependency: string +} + +export class BeamlineWatchpointReports extends Layout { getFormDependencies(): Dependency[] { return []; } component: FunctionComponent<{ [key: string]: any; }> = (props) => { - let b = new Dependency("watchpointReports.reports"); + let watchpointReportsDependency = new Dependency(this.config.watchpointReportsDependency); + let beamlineDependency = new Dependency(this.config.beamlineDependency); let formStateWrapper = useContext(CFormStateWrapper); - let accessor = new ModelsAccessor(formStateWrapper, [b]); - return (<>); + let accessor = new ModelsAccessor(formStateWrapper, [watchpointReportsDependency, beamlineDependency]); + let reportsValue: ArrayField = accessor.getFieldValue(watchpointReportsDependency) as any as ArrayField; + let elementsValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; + + let findElementById = (id: number) => elementsValue.find(e => e.item.id.value === id); + + let reportElements = (reportsValue as any[]).map((report, index) => { + let id = report.item.id.value; + let ele = findElementById(id); + let position = ele.item.position.value; + let cfg = createPanelConfig(`watchpointReport${index}`, `Intensity Report, ${position}`); + return { + id: id, + layout: LAYOUTS.getLayoutForSchema(cfg) + } + }).map((e, index) => { + let aliases: FormControllerAliases = [ + { + real: { + modelName: watchpointReportsDependency.modelName, + fieldName: watchpointReportsDependency.fieldName, + index + }, + fake: "watchpointReport", + realSchemaName: "watchpointReport" + } + ]; + let Comp = e.layout.component; + return ( + + + + + + ) + }) + + return (<>{ + reportElements + }); }; } + +function createPanelConfig(reportName: string, title: string) { + return { + "layout": "panel", + "config": { + "title": title, + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": reportName, + "dependencies": [ + "beamline.*", + "bendingMagnet.*", + "electronBeam.*", + "geometricSource.*", + "rayFilter.*", + "simulation.*", + "sourceDivergence.*", + "undulator.*", + "undulatorBeam.*", + "wiggler.*", + "initialIntensityReport.*" + ], + "reportLayout": { + "layout": "heatplot" + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Value to Plot", + "fields": [ + "watchpointReport.x", + "watchpointReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "watchpointReport.weight", + "watchpointReport.histogramBins", + "watchpointReport.overrideSize" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal Axis", + "Vertical Axis" + ], + "rows": [ + { + "label": "Horizontal Size [mm]", + "fields": [ + "watchpointReport.horizontalSize", + "watchpointReport.verticalSize" + ] + }, + { + "label": "Horizontal Offset [mm]", + "fields": [ + "watchpointReport.horizontalOffset", + "watchpointReport.verticalOffset" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "watchpointReport.aspectRatio", + "watchpointReport.colorMap", + "watchpointReport.notes" + ] + } + } + ] + } + } +} diff --git a/react/utility/convertschema.ts b/react/utility/convertschema.ts index aa38c4fe08..31776687a6 100644 --- a/react/utility/convertschema.ts +++ b/react/utility/convertschema.ts @@ -375,7 +375,7 @@ function fieldTableLayout( align: "left", text: name }), - fieldListLayout(fieldNames) + fieldListLayout(fieldNames.map(fn => fullFieldName(fn, modelName))) ] }) }) diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index bfb7f19e8b..556c741b2f 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -5135,6 +5135,13 @@ }, "_NAME": "initialIntensityReport" }, + { + "layout": "beamlineWatchpointReports", + "config": { + "beamlineDependency": "beamline.elements", + "watchpointReportsDependency": "watchpointReports.reports" + } + }, { "layout": "panel", "config": { diff --git a/sirepo/pkcli/shadow.py b/sirepo/pkcli/shadow.py index 21ba825509..6846b43ad4 100644 --- a/sirepo/pkcli/shadow.py +++ b/sirepo/pkcli/shadow.py @@ -10,11 +10,13 @@ from pykern.pkdebug import pkdp, pkdlog, pkdexc from sirepo import simulation_db from sirepo.template import template_common +import sirepo.sim_data import numpy import py.path import re import sirepo.template.shadow as template +_SIM_DATA, _, _ = sirepo.sim_data.template_globals() _MM_TO_CM = 0.1 _CM_TO_M = 0.01 @@ -120,7 +122,13 @@ def _run_beam_statistics(cfg_dir, data): def _run_shadow(cfg_dir, data): beam = template_common.exec_parameters().beam - model = data["models"][data["report"]] + r = data["report"] + model = None + if _SIM_DATA.is_watchpoint(r): + i = _SIM_DATA.watchpoint_id(r) + model = data["models"]["watchpointReports"]["reports"][i].item + else: + model = data["models"][data["report"]] column_values = _SCHEMA["enum"]["ColumnValue"] if "y" in model: diff --git a/sirepo/sim_data/shadow.py b/sirepo/sim_data/shadow.py index 0cac005fc3..0e0944e2b0 100644 --- a/sirepo/sim_data/shadow.py +++ b/sirepo/sim_data/shadow.py @@ -7,13 +7,71 @@ from __future__ import absolute_import, division, print_function from pykern.pkcollections import PKDict from pykern.pkdebug import pkdc, pkdlog, pkdp +from pykern import pkconfig +from pykern import pkjson import sirepo.sim_data import scipy.constants +import hashlib class SimData(sirepo.sim_data.SimDataBase): ANALYSIS_ONLY_FIELDS = frozenset(("colorMap", "notes", "aspectRatio")) + @classmethod + def compute_job_hash(cls, data, qcall): + """Hash fields related to data and set computeJobHash + + Only needs to be unique relative to the report, not globally unique + so MD5 is adequate. Long and cryptographic hashes make the + cache checks slower. + + Args: + data (dict): simulation data + changed (callable): called when value changed + Returns: + bytes: hash value + """ + cls._assert_server_side() + c = cls.compute_model(data) + if data.get("forceRun") or cls.is_parallel(c): + return "HashIsUnused" + m = data["models"] + res = hashlib.md5() + fields = sirepo.sim_data.get_class(data.simulationType)._compute_job_fields( + data, data.report, c + ) + # values may be string or PKDict + fields.sort(key=lambda x: str(x)) + for f in fields: + # assert isinstance(f, pkconfig.STRING_TYPES), \ + # 'value={} not a string_type'.format(f) + # TODO(pjm): work-around for now + if isinstance(f, pkconfig.STRING_TYPES): + x = f.split(".") + if cls.is_watchpoint(f) and f != "watchpointReports": + i = cls.watchpoint_id(f) + value = m.watchpointReports.reports[i].item + else: + value = m[x[0]][x[1]] if len(x) > 1 else m[x[0]] + else: + value = f + res.update( + pkjson.dump_bytes( + value, + sort_keys=True, + allow_nan=False, + ) + ) + res.update( + "".join( + ( + str(cls.lib_file_abspath(b, data=data, qcall=qcall).mtime()) + for b in sorted(cls.lib_file_basenames(data)) + ), + ).encode() + ) + return res.hexdigest() + @classmethod def fixup_old_data(cls, data, qcall, **kwargs): dm = data.models diff --git a/sirepo/template/shadow.py b/sirepo/template/shadow.py index 8b43116b7a..78d064be03 100644 --- a/sirepo/template/shadow.py +++ b/sirepo/template/shadow.py @@ -954,6 +954,7 @@ def _item_field(item, fields): def _parse_shadow_log(run_dir): if run_dir.join(template_common.RUN_LOG).exists(): text = pkio.read_text(run_dir.join(template_common.RUN_LOG)) + pkdp(text) for line in text.split("\n"): if re.search(r"invalid chemical formula", line): return "A mirror contains an invalid reflectivity material" From 173f25cae27a84a1795a935da3e2d9cbebe3e231 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 22 Mar 2023 22:12:00 +0000 Subject: [PATCH 14/68] fmt --- sirepo/sim_data/shadow.py | 23 +++++++++++------------ sirepo/template/shadow.py | 6 ++---- 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/sirepo/sim_data/shadow.py b/sirepo/sim_data/shadow.py index 0e0944e2b0..661abc3c53 100644 --- a/sirepo/sim_data/shadow.py +++ b/sirepo/sim_data/shadow.py @@ -96,25 +96,19 @@ def fixup_old_data(cls, data, qcall, **kwargs): ) if isinstance(dm.beamline, list): dm.beamline = PKDict( - elements=list(map(lambda i: PKDict( - model=i.type, - item=i - ), dm.beamline)) + elements=list(map(lambda i: PKDict(model=i.type, item=i), dm.beamline)) ) if not "watchpointReports" in dm: - dm.watchpointReports = PKDict( - reports=[] - ) + dm.watchpointReports = PKDict(reports=[]) n = [] for m in dm: if cls.is_watchpoint(m) and m != "watchpointReports": cls.update_model_defaults(dm[m], "watchpointReport") i = cls.watchpoint_id(m) dm[m].id = i - dm.watchpointReports.reports.append(PKDict( - model="watchpointReport", - item=dm[m] - )) + dm.watchpointReports.reports.append( + PKDict(model="watchpointReport", item=dm[m]) + ) n.append(m) for i in n: del dm[i] @@ -148,7 +142,12 @@ def _compute_job_fields(cls, data, r, compute_model): "undulatorBeam", "wiggler", ] - if r == "initialIntensityReport" and data["models"]["beamline"] and data["models"]["beamline"]["elements"] and len(data["models"]["beamline"]["elements"]) > 0: + if ( + r == "initialIntensityReport" + and data["models"]["beamline"] + and data["models"]["beamline"]["elements"] + and len(data["models"]["beamline"]["elements"]) > 0 + ): res.append([data["models"]["beamline"]["elements"][0]["item"]["position"]]) # TODO(pjm): only include items up to the current watchpoint if cls.is_watchpoint(r) or r == "beamStatisticsReport": diff --git a/sirepo/template/shadow.py b/sirepo/template/shadow.py index 78d064be03..a5f77d807f 100644 --- a/sirepo/template/shadow.py +++ b/sirepo/template/shadow.py @@ -731,7 +731,7 @@ def _generate_parameters_file(data, run_dir=None, is_parallel=False): v = template_common.flatten_data(data.models, PKDict()) r = data.report - #report_model = data.models[r] + # report_model = data.models[r] beamline = list(map(lambda i: i.item, data.models.beamline.elements)) v.shadowOutputFile = _SHADOW_OUTPUT_FILE if _has_zone_plate(beamline): @@ -783,9 +783,7 @@ def _generate_parameters_file(data, run_dir=None, is_parallel=False): elif _SIM_DATA.is_watchpoint(r): di = _SIM_DATA.watchpoint_id(r) rd = data.models.watchpointReports.reports[di] - v.beamlineOptics = _generate_beamline_optics( - data.models, last_id=rd.item.id - ) + v.beamlineOptics = _generate_beamline_optics(data.models, last_id=rd.item.id) else: v.distanceFromSource = data.models[r].distanceFromSource return template_common.render_jinja(SIM_TYPE, v) From 5262bc7e3694d604d374adf0585cf61942025c8e Mon Sep 17 00:00:00 2001 From: git-user Date: Thu, 23 Mar 2023 21:40:47 +0000 Subject: [PATCH 15/68] simplify and fix waterfall layout --- react/src/layout/arrange/waterfall.tsx | 202 +++++++----------------- react/src/layout/report/histogram2d.tsx | 2 +- react/src/utility/component.ts | 32 +++- 3 files changed, 83 insertions(+), 153 deletions(-) diff --git a/react/src/layout/arrange/waterfall.tsx b/react/src/layout/arrange/waterfall.tsx index 9073bf8955..0a489521d6 100644 --- a/react/src/layout/arrange/waterfall.tsx +++ b/react/src/layout/arrange/waterfall.tsx @@ -1,14 +1,11 @@ -import { FunctionComponent, useRef, useState } from "react"; +import { FunctionComponent, MutableRefObject, RefObject, useLayoutEffect, useRef, useState } from "react"; import { Dependency } from "../../data/dependency"; import { SchemaLayout } from "../../utility/schema"; import { Layout, LayoutProps } from "../layout"; import { LAYOUTS } from "../layouts"; -import { Dimension, useRefSize } from "../../utility/component"; import React from "react"; import { Breakpoint, resolveBreakpoint, useWindowSize } from "../../hook/breakpoint"; -import { VerticalStack } from "../../component/reusable/stack"; import "./waterfall.scss"; -import { debounce } from "../../utility/debounce"; export type WaterfallConfig = { @@ -20,67 +17,14 @@ export type WaterfallConfig = { } } -export type WaterfallRef = { - element: JSX.Element, - dimension: Dimension, - ref: React.RefObject -} - -type WaterfallBin = { - calculatedSize: number, - items: WaterfallRef[]; -} - -class WaterfallController { - private refs: WaterfallRef[]; - private breakpoint: Breakpoint; - private windowSize: number; - private waterfallBins: WaterfallBin[]; - private hasAllSizes: boolean = false; - - constructor(private config: WaterfallConfig) {} - - assignViewsToBinsSerial = () => { - this.refs.forEach((r, idx) => { - let bi = idx % this.waterfallBins.length; - this.waterfallBins[bi].items.push(r); - }) - } - - windowSizeUpdateCallback = debounce((s: number) => { - this.windowSize = s; - this.assignViewsToBins(); - }, 250) - - assignViewsToBins = () => { - this.waterfallBins.forEach(bin => bin.items = []); - - if(!this.hasAllSizes) { - this.assignViewsToBinsSerial(); - return; - } +export class WaterfallLayout extends Layout { + children: Layout[]; - let findSmallestBinSmallerThan = (s: number) => { - return this.waterfallBins.filter(b => b.calculatedSize < s).reduce((prev, cur) => { - if(!prev) { - return cur; - } - if(cur.calculatedSize < prev.calculatedSize) { - return cur; - } - return prev; - }, undefined); - } - - for(let ri = 0; ri < this.refs.length; ri++) { - let ref = this.refs[ri]; - let s = ref.dimension.height; - let bin = this.waterfallBins[ri % this.waterfallBins.length]; - //let betterBin = findSmallestBinSmallerThan(bin.calculatedSize - s); // TODO: this resizing works but it appears buggy to the user, need better algorithm - //bin = betterBin || bin; - bin.items.push(ref); - bin.calculatedSize += s; - } + constructor(config: WaterfallConfig) { + super(config); + this.children = (config.items || []).map(schemaLayout => { + return LAYOUTS.getLayoutForSchema(schemaLayout); + }); } numBinsForBreakpoint(breakpoint: Breakpoint) { @@ -103,65 +47,14 @@ class WaterfallController { return bins; } - createBins = (n: number) => { - this.waterfallBins = []; - for(let i = 0; i < n; i++) { - this.waterfallBins.push({ - calculatedSize: 0, - items: [] - }); - } - } - - updateRefs = (refs: WaterfallRef[], windowSize: number) => { - let breakpoint = resolveBreakpoint(windowSize); - let hasAllSizes = !refs.map(ref => !!ref.dimension).includes(false); - this.refs = refs; - //this.refs = refs; - - if(this.breakpoint !== breakpoint) { - // redo bins - this.createBins(this.numBinsForBreakpoint(breakpoint)); - // redo assignment - this.assignViewsToBins(); - } else { - - // if gained completeness, redo assignment - if(!this.hasAllSizes && hasAllSizes) { - this.hasAllSizes = hasAllSizes; - this.assignViewsToBins(); - } - // if changed window size, redo assignment - if(this.windowSize !== windowSize) { - this.windowSizeUpdateCallback(windowSize); - } - } - - this.breakpoint = breakpoint; - this.windowSize = windowSize; - - return this.waterfallBins; - } -} - -export class WaterfallLayout extends Layout { - children: Layout[]; - - constructor(config: WaterfallConfig) { - super(config); - this.children = (config.items || []).map(schemaLayout => { - return LAYOUTS.getLayoutForSchema(schemaLayout); - }); - } - getFormDependencies(): Dependency[] { return (this.children || []).flatMap(c => c.getFormDependencies()); } - getMarginStyles = (): {[key: string]: string} => { + getMarginStyles = (): string => { if(!this.config.gutters) { - return {}; + return ""; } let formatValue = (v: number | string) => { @@ -174,55 +67,74 @@ export class WaterfallLayout extends Layout { let ret = {}; if(this.config.gutters.horizontal) { let h = formatValue(this.config.gutters.horizontal); - ret['marginLeft'] = h; - ret['marginRight'] = h; + ret['margin-left'] = h; + ret['margin-right'] = h; } if(this.config.gutters.vertical) { let v = formatValue(this.config.gutters.vertical); - ret['marginTop'] = v; - ret['marginBottom'] = v; + ret['margin-top'] = v; + ret['margin-bottom'] = v; } - return ret; + return Object.entries(ret).map(([name, value]) => `${name}: ${value}`).join("; ") } component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { - let windowSize = useWindowSize(); - let c: WaterfallRef[] = this.children.map((c, idx) => { - let componentRef = useRef() - let [dim,] = useRefSize(componentRef); + let breakpoint = resolveBreakpoint(windowSize); + let c: JSX.Element[] = this.children.map((c, idx) => { let LayoutComponent = c.component; - return { - element: ( -
- -
- ), - dimension: dim, - ref: componentRef - } + return }); - let [controller, ] = useState(() => new WaterfallController(this.config)); - let bins = controller.updateRefs(c, windowSize); + let numBins = this.numBinsForBreakpoint(breakpoint); - let eles = bins.map((bin, idx) => { - return ( - - {bin.items.map(item => item.element)} - - ) - }) + let bins: JSX.Element[] = []; + let binRefs: RefObject[] = []; + for(let b = 0; b < numBins; b++) { + let ref = useRef(); + bins.push(
+ +
) + binRefs.push(ref); + } let gridStyle = { "gridTemplateColumns": bins.map(() => `${(100/bins.length).toFixed(2)}%`).join(" "), "gridTemplateRows": "1fr" } + let containerRef = useRef(); + + useLayoutEffect(() => { + for(let r of binRefs) { + if(!r.current) { + console.log("bin was not defined"); + return; + } + } + + if(!containerRef.current) { + console.log("container was not defined"); + return; + } + + let container = containerRef.current; + // needs to be done this way, avoids mutating length during for loop + let children = Array.from(container.children); + children.forEach((e, i) => { + let b = binRefs[i % binRefs.length].current; + b.appendChild(e); + e.setAttribute("style", this.getMarginStyles()) + }) + }) + return (
- {eles} +
+ {c} +
+ {bins}
) }; diff --git a/react/src/layout/report/histogram2d.tsx b/react/src/layout/report/histogram2d.tsx index b6d4ca1769..fb3692c164 100644 --- a/react/src/layout/report/histogram2d.tsx +++ b/react/src/layout/report/histogram2d.tsx @@ -13,7 +13,7 @@ export type Histogram2dConfigApi = { } export function apiResponseHistogramToGraph2dConfig(cfg: Histogram2dConfigApi): Graph2dConfig { - if(!cfg) return undefined; + if(!cfg || !cfg.x_range) return undefined; // TODO: put in schema or get from server let color = "#006699"; diff --git a/react/src/utility/component.ts b/react/src/utility/component.ts index 740b70719f..24106df019 100644 --- a/react/src/utility/component.ts +++ b/react/src/utility/component.ts @@ -37,6 +37,28 @@ export type Dimension = { width: number } +export function getElementSize(e: HTMLElement): Dimension { + if(!e || !e.offsetWidth) { + return undefined; + } + + const w = e.offsetWidth; + const h = e.offsetHeight; + + return { + width: w, + height: h + } +} + +export function getRefSize(ref: RefObject): Dimension { + if (! ref || ! ref.current || ! ref.current.offsetWidth) { + return undefined; + } + + return getElementSize(ref.current); +} + export function useRefSize(ref: RefObject): [Dimension, React.Dispatch>] { const [dim, setDim] = useState({ width: 1000, @@ -48,14 +70,10 @@ export function useRefSize(ref: RefObject): [Dimension, React.Dispa } // cannot read from ref inside debounce, debounce is called with a delay... // need to cache future answers and check for staleness in callback - const w = ref.current.offsetWidth; - const h = ref.current.offsetHeight; + let newDim = getRefSize(ref); const handleResize = debounce(() => { - if (dim.width !== w) { - setDim({ - width: w, - height: h, - }); + if (dim.width !== newDim.width) { + setDim(newDim); } }, 250); window.addEventListener('resize', handleResize); From c6507c324b3f3d6532b2a0c3977536441378c8b3 Mon Sep 17 00:00:00 2001 From: git-user Date: Thu, 23 Mar 2023 22:11:18 +0000 Subject: [PATCH 16/68] fix layout render order and cleanup --- react/src/component/reusable/graph2d.tsx | 2 + react/src/component/reusable/heatplot.tsx | 2 + react/src/layout/arrange/waterfall.tsx | 73 ++++++++++++++--------- 3 files changed, 49 insertions(+), 28 deletions(-) diff --git a/react/src/component/reusable/graph2d.tsx b/react/src/component/reusable/graph2d.tsx index 21c669938c..7319105726 100644 --- a/react/src/component/reusable/graph2d.tsx +++ b/react/src/component/reusable/graph2d.tsx @@ -5,6 +5,7 @@ import { LegendOrdinal } from "@visx/legend"; import { Point2d, Range1d } from '../../types'; import { Zoom } from '@visx/zoom'; import { constrainZoom, useGraphContentBounds } from "../../utility/component"; +import { useWindowSize } from '../../hook/breakpoint'; export type Graph2dPlot = { color: string, @@ -26,6 +27,7 @@ export function Graph2d(props: Graph2dConfig) { const ref = useRef(null); //TODO(pjm): use props.aspectRatio if present const gc = useGraphContentBounds(ref, 9 / 16.0); + useWindowSize(); // needs to resize when window does function constrain(transformMatrix) { // no Y zoom diff --git a/react/src/component/reusable/heatplot.tsx b/react/src/component/reusable/heatplot.tsx index 16b8eac74e..f71e803474 100644 --- a/react/src/component/reusable/heatplot.tsx +++ b/react/src/component/reusable/heatplot.tsx @@ -7,6 +7,7 @@ import { Scale } from '@visx/visx'; import { Zoom } from '@visx/zoom'; import { constrainZoom, createColorScale, useGraphContentBounds } from "../../utility/component"; import { rgb } from 'd3-color'; +import { useWindowSize } from '../../hook/breakpoint'; export type HeatPlotConfig = { title: string, @@ -67,6 +68,7 @@ function HeatplotImage({ xScaleDomain, yScaleDomain, xRange, yRange, width, heig export function Heatplot({title, xRange, yRange, zRange, xLabel, yLabel, zMatrix, colorMap }: HeatPlotConfig & HeatPlotConfigExtras) { const ref = useRef(null); + useWindowSize(); // needs to resize when window does colorMap = colorMap || 'viridis'; const showColorBar = colorMap !== 'contrast'; //TODO(pjm): use props.aspectRatio if present diff --git a/react/src/layout/arrange/waterfall.tsx b/react/src/layout/arrange/waterfall.tsx index 0a489521d6..0cac4bd931 100644 --- a/react/src/layout/arrange/waterfall.tsx +++ b/react/src/layout/arrange/waterfall.tsx @@ -1,4 +1,4 @@ -import { FunctionComponent, MutableRefObject, RefObject, useLayoutEffect, useRef, useState } from "react"; +import { FunctionComponent, MutableRefObject, RefObject, useEffect, useLayoutEffect, useRef, useState } from "react"; import { Dependency } from "../../data/dependency"; import { SchemaLayout } from "../../utility/schema"; import { Layout, LayoutProps } from "../layout"; @@ -79,24 +79,16 @@ export class WaterfallLayout extends Layout { return Object.entries(ret).map(([name, value]) => `${name}: ${value}`).join("; ") } - component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { + waterfallBins = (props: { children: React.ReactNode }) => { let windowSize = useWindowSize(); let breakpoint = resolveBreakpoint(windowSize); - let c: JSX.Element[] = this.children.map((c, idx) => { - let LayoutComponent = c.component; - return - }); - let numBins = this.numBinsForBreakpoint(breakpoint); let bins: JSX.Element[] = []; - let binRefs: RefObject[] = []; for(let b = 0; b < numBins; b++) { - let ref = useRef(); - bins.push(
+ bins.push(
) - binRefs.push(ref); } let gridStyle = { @@ -104,38 +96,63 @@ export class WaterfallLayout extends Layout { "gridTemplateRows": "1fr" } - let containerRef = useRef(); - - useLayoutEffect(() => { - for(let r of binRefs) { - if(!r.current) { - console.log("bin was not defined"); - return; - } - } - + useEffect(() => { + console.log("bins.length", bins.length); if(!containerRef.current) { console.log("container was not defined"); - return; + return () => {}; } + if(!waterfallRef.current) { + console.log("waterfall was not defined"); + return () => {}; + } + + let binEles = Array.from(waterfallRef.current.children); + let container = containerRef.current; // needs to be done this way, avoids mutating length during for loop let children = Array.from(container.children); + let cleanups = []; children.forEach((e, i) => { - let b = binRefs[i % binRefs.length].current; + let b = binEles[i % binEles.length]; b.appendChild(e); e.setAttribute("style", this.getMarginStyles()) + cleanups.push(() => { + container.appendChild(e); + }) }) - }) + + return () => cleanups.forEach(c => c()) + }, [bins.length]) + + let waterfallRef = useRef(); + let containerRef = useRef(); return ( -
+ <> +
+ {bins} +
- {c} + {props.children}
- {bins} -
+ + ) + } + + component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { + + let c: JSX.Element[] = this.children.map((c, idx) => { + let LayoutComponent = c.component; + return + }); + + + let WaterfallBins = this.waterfallBins; + + return ( + {c} ) }; } From 2d671ed8cd76060dc278234d2e64384dd5c095e2 Mon Sep 17 00:00:00 2001 From: git-user Date: Thu, 23 Mar 2023 22:30:05 +0000 Subject: [PATCH 17/68] remove console logs and fix wiggler beamline --- react/src/layout/arrange/waterfall.tsx | 3 --- react/src/layout/beamline.tsx | 10 ---------- react/src/layout/panel.tsx | 14 +++++++++++--- react/src/layout/report.tsx | 5 ++++- react/src/utility/download.ts | 1 - .../static/react-json/shadow-schema.json | 1 + 6 files changed, 16 insertions(+), 18 deletions(-) diff --git a/react/src/layout/arrange/waterfall.tsx b/react/src/layout/arrange/waterfall.tsx index 0cac4bd931..d44098632c 100644 --- a/react/src/layout/arrange/waterfall.tsx +++ b/react/src/layout/arrange/waterfall.tsx @@ -97,14 +97,11 @@ export class WaterfallLayout extends Layout { } useEffect(() => { - console.log("bins.length", bins.length); if(!containerRef.current) { - console.log("container was not defined"); return () => {}; } if(!waterfallRef.current) { - console.log("waterfall was not defined"); return () => {}; } diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 8a92e69a21..14bd1f44ff 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -50,11 +50,6 @@ export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: let modelsWrapper = useContext(CModelsWrapper); let schema = useContext(CSchema); - // TODO: override form controller - //console.log("ele", ele); - //console.log("id", id); - console.log("modalShown", modalShown); - let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); let isDirty = formController.isFormStateDirty(); @@ -99,7 +94,6 @@ export class BeamlineLayout extends Layout { } component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { - console.log("RENDER"); let routeHelper = useContext(CRouteHelper); let formStateWrapper = useContext(CFormStateWrapper); let modelsWrapper = useContext(CModelsWrapper); @@ -111,7 +105,6 @@ export class BeamlineLayout extends Layout { let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); let [shownModal, updateShownModal] = useState(undefined); - console.log("shownModal", shownModal); let accessor = new ModelsAccessor(formStateWrapper, [beamlineDependency]); @@ -146,8 +139,6 @@ export class BeamlineLayout extends Layout { ) }) - //console.log("elements", this.elements); - let findBaseElementByModel = (model: string) => { let r = this.elements.filter(e => e.model === model); if(r.length > 1) { @@ -156,7 +147,6 @@ export class BeamlineLayout extends Layout { return r[0]; } - //console.log("beamlineValue", beamlineValue); let beamlineComponents = beamlineValue.map((e, i) => { let model = e.model; let ele: FormModelState = e.item; diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index f178efde1d..2894546e5a 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -10,11 +10,13 @@ import { CModelsWrapper, ModelsWrapper } from "../data/wrapper"; import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; +import { useShown } from "../hook/shown"; export type PanelConfig = { basic: SchemaLayout[], advanced: SchemaLayout[], - title: string + title: string, + shown: string } export class PanelLayout extends Layout { @@ -37,6 +39,8 @@ export class PanelLayout extends Layout { let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); + let shown = useShown(this.config.shown, true, modelsWrapper, ValueSelectors.Models); + let store = useStore(); let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); @@ -69,8 +73,12 @@ export class PanelLayout extends Layout { } return ( - - + <> + { + shown && + } + + ) } } diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index e275874555..fbb8402707 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -19,6 +19,8 @@ import { CAppName, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { CRouteHelper } from "../utility/route"; import { ModelState } from "../store/models"; +import { useShown } from "../hook/shown"; +import { ValueSelectors } from "../utility/string"; export type ReportVisualProps = { data: L, model: ModelState }; @@ -202,11 +204,12 @@ export class ManualRunReportLayout extends Layout { : true; let modelsWrapper = useContext(CModelsWrapper); let store = useStore(); + let shown = useShown(this.config.shown, true, modelsWrapper, ValueSelectors.Models); let model = getModelValues([reportName], modelsWrapper, store.getState())[reportName]; let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); return ( <> - {this.reportLayout && + {shown && this.reportLayout && animationReader && { diff --git a/react/src/utility/download.ts b/react/src/utility/download.ts index 341e5b929b..ea481d52cc 100644 --- a/react/src/utility/download.ts +++ b/react/src/utility/download.ts @@ -12,6 +12,5 @@ export function downloadAs(blob: Blob, fileName: string) { export function getAttachmentFileName(response: Response) { let pattern = /filename=["]?([\w.\-_]+)["]?/g let match = pattern.exec(response.headers.get('content-disposition')); - console.log("match", match); return match[1]; } diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index 556c741b2f..c216048704 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -5146,6 +5146,7 @@ "layout": "panel", "config": { "title": "Beam Statistics", + "shown": "$(simulation.sourceType) == 'bendingMagnet' || $(simulation.sourceType) == 'geometricSource' || $(simulation.sourceType) == 'undulator'", "basic": [ { "layout": "autoRunReport", From 60c311be7c1d3de3db4a87b2a8a8d4715c133393 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 23 Mar 2023 22:31:50 +0000 Subject: [PATCH 18/68] test commit --- react/src/layout/form.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index 1bd93c321f..d395c2f6b8 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -192,11 +192,11 @@ export function arrayPositionHandle(modelsWrapper: AbstractModelsWrapper { + getModel: (_: string, state: any): M => { let m = modelsWrapper.getModel(realArrayDep.modelName, state); return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; }, - hookModel: (modelName: string): M => { + hookModel: (_: string): M => { let m = modelsWrapper.hookModel(realArrayDep.modelName); return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; } From c1788f28519f42e70504bed972402f552b5a4874 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 30 Mar 2023 00:14:31 +0000 Subject: [PATCH 19/68] wip refactor data to be more flexible --- react/src/component/app.tsx | 2 +- react/src/component/reusable/input.tsx | 2 +- react/src/component/simulation.tsx | 13 +- react/src/data/accessor.ts | 48 ----- react/src/data/data.ts | 30 +++ react/src/data/dependency.ts | 16 +- react/src/data/formController.ts | 128 ------------- react/src/data/handle.ts | 90 +++++++++ react/src/data/saver.ts | 36 ++++ react/src/data/wrapper.ts | 243 ------------------------- react/src/layout/beamline.tsx | 25 +-- react/src/layout/form.tsx | 27 ++- react/src/layout/input/array.tsx | 7 - react/src/layout/report.tsx | 12 +- react/src/store/common.ts | 64 +++++++ react/src/store/formState.ts | 42 +---- react/src/store/models.ts | 47 +---- react/src/utility/string.ts | 20 +- 18 files changed, 289 insertions(+), 563 deletions(-) delete mode 100644 react/src/data/accessor.ts create mode 100644 react/src/data/data.ts delete mode 100644 react/src/data/formController.ts create mode 100644 react/src/data/handle.ts create mode 100644 react/src/data/saver.ts delete mode 100644 react/src/data/wrapper.ts create mode 100644 react/src/store/common.ts diff --git a/react/src/component/app.tsx b/react/src/component/app.tsx index b1581f6512..9dfccc0926 100644 --- a/react/src/component/app.tsx +++ b/react/src/component/app.tsx @@ -14,7 +14,7 @@ import { CRouteHelper, RouteHelper } from "../utility/route"; import { getAppCombinedSchema } from "../utility/schema"; export const AppContextWrapper = (props) => { - const modelsStore = configureStore({ + const modelsStore = configureStore({ // TODO: this belongs on the simulation root component reducer: { [modelsSlice.name]: modelsSlice.reducer, [formStatesSlice.name]: formStatesSlice.reducer, diff --git a/react/src/component/reusable/input.tsx b/react/src/component/reusable/input.tsx index f02277252e..a56bf26210 100644 --- a/react/src/component/reusable/input.tsx +++ b/react/src/component/reusable/input.tsx @@ -28,7 +28,7 @@ export function FieldInput(props: FieldProps) { return ( diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 09ceb82a08..dcc3cbae81 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -11,18 +11,15 @@ import React, { import { modelSelectors, modelActions, - ModelState, - ModelStates + ModelState } from "../store/models"; import { FormStateInitializer } from "./reusable/form"; import { useNavigate, useResolvedPath } from "react-router-dom"; import { CRelativeRouterHelper, CRouteHelper, RelativeRouteHelper } from "../utility/route"; import { ReportEventManager } from "../data/report"; import { CReportEventManager } from "../data/report"; -import { CModelsWrapper, ModelsWrapper } from "../data/wrapper"; import { CAppName, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { LAYOUTS } from "../layout/layouts"; -import { ModelsAccessor } from "../data/accessor"; import { Dependency } from "../data/dependency"; import { NavbarRightContainerId, NavToggleDropdown } from "./reusable/navbar"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -31,9 +28,10 @@ import { useSetup } from "../hook/setup"; import { Portal } from "./reusable/portal"; import { downloadAs, getAttachmentFileName } from "../utility/download"; import { useStore } from "react-redux"; +import { StoreState } from "../store/common"; export type SimulationInfoRaw = { - models: ModelStates, + models: StoreState, simulationType: string, version: string } @@ -51,11 +49,6 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let routeHelper = useContext(CRouteHelper); let store = useStore(); - let modelsWrapper = new ModelsWrapper({ - modelActions, - modelSelectors - }) - useEffect(() => { updateSimulationInfoPromise(new Promise((resolve, reject) => { fetch(routeHelper.globalRoute("simulationData", { diff --git a/react/src/data/accessor.ts b/react/src/data/accessor.ts deleted file mode 100644 index 2c6dedfacd..0000000000 --- a/react/src/data/accessor.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { ModelStates } from "../store/models"; -import { Dependency } from "./dependency"; -import { AbstractModelsWrapper } from "./wrapper"; - -export class ModelsAccessor { - modelValues: {[key: string]: M}; - modelNames: string[]; - constructor(private modelsWrapper: AbstractModelsWrapper, private dependencies: Dependency[]) { - this.modelNames = [...new Set(dependencies.map(d => d.modelName))]; - this.modelValues = Object.fromEntries(this.modelNames.map(modelName => { - return [ - modelName, - modelsWrapper.hookModel(modelName) - ] - })) - - // expand wildcard - this.dependencies = this.dependencies.flatMap(d => { - if(d.fieldName === '*') { - let fieldNames = Object.keys(this.modelValues[d.modelName]); - return fieldNames.map(fn => new Dependency(`${d.modelName}.${fn}`)); - } else { - return [d]; - } - }) - } - - getFieldValue = (dependency: Dependency): F => { - return this.modelsWrapper.getFieldFromModel(dependency.fieldName, this.getModelValue(dependency.modelName)); - } - - getModelValue = (modelName: string): M => { - return this.modelValues[modelName]; - } - - getValues = (): { dependency: Dependency, value: F }[] => { - return this.dependencies.map(d => { - return { - dependency: d, - value: this.getFieldValue(d) - } - }) - } - - getModelNames = (): string[] => { - return this.modelNames; - } -} diff --git a/react/src/data/data.ts b/react/src/data/data.ts new file mode 100644 index 0000000000..3d00b7ad20 --- /dev/null +++ b/react/src/data/data.ts @@ -0,0 +1,30 @@ +import { ModelSelector, ModelWriteActionCreator } from "../store/common"; +import { formActions, FormFieldState, formSelectors } from "../store/formState"; +import { modelActions, modelSelectors } from "../store/models"; + +export enum StoreType { + Models, + FormState +} + +export const getModelReadSelector = (type: StoreType) => { + return (type === StoreType.Models ? modelSelectors.selectModel : formSelectors.selectModel) as ModelSelector; +} +export const getModelWriteActionCreator = (type: StoreType) => { + let mac = (type === StoreType.Models ? modelActions.updateModel : formActions.updateModel) as ModelWriteActionCreator; + return (name: string, value: V) => mac({ name, value }); +} +export const getModelNamesSelector = (type: StoreType) => { + return (type === StoreType.Models ? modelSelectors.selectModelNames : formSelectors.selectModelNames); +} + +export type ValueSelector = (v: T) => any; + +export const ValueSelectors = { + Models: (v: any) => v, + Fields: (v: FormFieldState) => v.value +} + +export const getValueSelector = (storeType: StoreType): ((v: any) => any) | ((v: FormFieldState) => unknown) => { + return storeType === StoreType.Models ? ValueSelectors.Models : ValueSelectors.Fields; +} diff --git a/react/src/data/dependency.ts b/react/src/data/dependency.ts index cdcd2d06f8..c7b8eab14f 100644 --- a/react/src/data/dependency.ts +++ b/react/src/data/dependency.ts @@ -1,28 +1,22 @@ export class Dependency { modelName: string; fieldName: string; - index?: number; - subFieldName?: string; constructor(dependencyString: string) { - let { modelName, fieldName, index, subFieldName } = this.mapDependencyNameToParts(dependencyString); + let { modelName, fieldName } = this.mapDependencyNameToParts(dependencyString); this.modelName = modelName; this.fieldName = fieldName; - this.index = index; - this.subFieldName = subFieldName; } - mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string, index?: number, subFieldName?: string } = (dep) => { - let [modelName, fieldName, index, subFieldName] = dep.split('.').filter((s: string) => s && s.length > 0); + mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string } = (dep) => { + let [modelName, fieldName] = dep.split('.').filter((s: string) => s && s.length > 0); return { modelName, - fieldName, - index: parseInt(index), - subFieldName + fieldName } } getDependencyString: () => string = () => { - return this.modelName + "." + this.fieldName + (this.index ? `@${this.index}` : ''); + return this.modelName + "." + this.fieldName; } } diff --git a/react/src/data/formController.ts b/react/src/data/formController.ts deleted file mode 100644 index 1041fac3e9..0000000000 --- a/react/src/data/formController.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { mapProperties } from "../utility/object"; -import React from "react"; -import { FormFieldState, FormModelState } from "../store/formState"; -import { Dependency } from "./dependency"; -import { ModelState } from "../store/models"; -import { Schema, SchemaModel } from "../utility/schema"; -import { ModelsAccessor } from "./accessor"; -import { AbstractModelsWrapper } from "./wrapper"; -import { InputLayout } from "../layout/input/input"; - - - -export let formStateFromModel = (model: ModelState, modelSchema: SchemaModel, schema: Schema) => { - if(!modelSchema) { - throw new Error(`while converting model to form state, model schema was undefiend; model=${JSON.stringify(model)}`); - } - if(!model) { - throw new Error(`while converting model to form state, model was undefined; schema=${JSON.stringify(modelSchema)}`); - } - // TODO: should this be mapping from schema or from the model being mapped? - return mapProperties(modelSchema, (fieldName, { type }) => { - if(!(fieldName in model)) { - if(modelSchema[fieldName].defaultValue !== undefined) { - model[fieldName] = modelSchema[fieldName].defaultValue; - } else { - throw new Error(`model=${JSON.stringify(model)} was missing field=${fieldName}`) - } - } - - let mv = model[fieldName]; - if(mv.constructor && mv.constructor.name == "Array") { - let v: {item: ModelState, model: string}[] = mv as any[] || []; - return v.map(i => { - return { - item: formStateFromModel(i.item, schema.models[i.model], schema), - model: i.model - } - }) - } - - return { - valid: type.validate(model[fieldName]), - value: type.fromModelValue(model[fieldName]), - touched: false, - active: true - } - }) -} - -export const CFormController = React.createContext(undefined); - -export function fieldStateFromValue(value: any, lastState: FormFieldState, type: InputLayout): FormFieldState { - return { - valid: type.validate(value), - value, - active: lastState.active, - touched: true - } -} - -export class FormController { - formStatesAccessor: ModelsAccessor>; - modelStatesAccessor: ModelsAccessor; - constructor( - private formStatesWrapper: AbstractModelsWrapper>, - private modelsWrapper: AbstractModelsWrapper, - private dependencies: Dependency[], - private schema: Schema - ) { - this.formStatesAccessor = new ModelsAccessor(formStatesWrapper, dependencies); - this.modelStatesAccessor = new ModelsAccessor(modelsWrapper, dependencies) - } - - saveToModels = (state: any) => { - let f = this.formStatesAccessor.getValues(); - this.formStatesAccessor.getModelNames().map(mn => { - return { - modelName: mn, - changes: Object.fromEntries(f.filter(v => v.dependency.modelName == mn).map(mv => { - let modelSchema = this.schema.models[mn]; - let v = modelSchema[mv.dependency.fieldName].type.toModelValue(mv.value.value); - return [ - mv.dependency.fieldName, - v - ] - })) - } - }).forEach(modelChanges => { - let m = this.modelStatesAccessor.getModelValue(modelChanges.modelName); - m = {...m}; //copy - Object.assign(m, modelChanges.changes); - - console.log("submitting value ", m, " to ", modelChanges.modelName); - this.modelsWrapper.updateModel(modelChanges.modelName, m, state); - // this should make sure that if any part of the reducers are inconsistent / cause mutations - // then the form state should remain consistent with saved model copy - // TODO: this line has been changed with recent update, evaluate - this.formStatesWrapper.updateModel(modelChanges.modelName, formStateFromModel(m, this.schema.models[modelChanges.modelName], this.schema), state) - }) - } - - getFormStateAccessor = (): ModelsAccessor> => { - return this.formStatesAccessor; - } - - getModelsAccessor = (): ModelsAccessor => { - return this.modelStatesAccessor; - } - - getDependencies = (): Dependency[] => { - return this.dependencies; - } - - cancelChanges = (state: any) => { - this.formStatesAccessor.modelNames.map(modelName => { - return this.formStatesWrapper.updateModel(modelName, formStateFromModel( - this.modelStatesAccessor.getModelValue(modelName), - this.schema.models[modelName], this.schema), state); - }); - } - - isFormStateDirty = () => { - return this.formStatesAccessor.getValues().map(fv => !!fv.value.touched).includes(true); - } - isFormStateValid = () => { - return !this.formStatesAccessor.getValues().map(fv => !!fv.value.valid).includes(false); - } -} diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts new file mode 100644 index 0000000000..0572c688aa --- /dev/null +++ b/react/src/data/handle.ts @@ -0,0 +1,90 @@ +import { useSelector } from "react-redux"; +import { AnyAction, Dispatch } from "redux"; +import { ArrayFieldElement, ArrayFieldState } from "../store/common"; +import { getModelReadSelector, getModelWriteActionCreator, StoreType } from "./data"; + +export abstract class DataHandle { + constructor(protected currentValue: V) { + this.value = currentValue; + } + + abstract write(value: V, dispatch: Dispatch); + readonly value: V; +} + +export abstract class ArrayDataHandle> extends DataHandle { + abstract append(element: ArrayFieldElement, dispatch: Dispatch); + abstract appendAt(index: number, element: ArrayFieldElement, dispatch: Dispatch); + abstract removeAt(index: number, dispatch: Dispatch); +} + +export interface EmptyDataHandle = DataHandle> { + /** + * use the current state to populate the data in the handle without subscribing to updates + * @param state current state + */ + initialize(state: any): D; + /** + * create handle using selector hooks, subscribes to data updates where these hooks are called + */ + hook(): D; +} + +export abstract class HandleFactory { + abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; + abstract createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle; +} + +export class BaseHandleFactory extends HandleFactory { + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + let ms = getModelReadSelector(type)(dependency.modelName); + let mac = getModelWriteActionCreator(type); + let cdh = (value: V): DataHandle => { + return new (class extends DataHandle { + write = (value: V, dispatch: Dispatch) => { + dispatch(mac(dependency.modelName, value)); + } + })(value); + } + return { + initialize: (state: any) => { + return cdh(ms(state)); + }, + hook: () => { + return cdh(useSelector(ms)); + } + } + } + + createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { + let ms = getModelReadSelector(type)(dependency.modelName); + let mac = getModelWriteActionCreator(type); + let cdh = (value: V): ArrayDataHandle => { + return new (class extends ArrayDataHandle { + write = (value: V, dispatch: Dispatch) => { + dispatch(mac(dependency.modelName, value)); + } + appendAt = (index: number, element: ArrayFieldElement, dispatch: Dispatch) => { + this.currentValue.splice(index, 0, element); + this.write(this.currentValue, dispatch); + } + append = (element: ArrayFieldElement, dispatch: Dispatch) => { + this.currentValue.push(element); + this.write(this.currentValue, dispatch); + } + removeAt = (index: number, dispatch: Dispatch) => { + this.currentValue.splice(index, 1); + this.write(this.currentValue, dispatch); + } + })(value); + } + return { + initialize: (state: any) => { + return cdh(ms(state)); + }, + hook: () => { + return cdh(useSelector(ms)); + } + } + } +} diff --git a/react/src/data/saver.ts b/react/src/data/saver.ts new file mode 100644 index 0000000000..683e912ecb --- /dev/null +++ b/react/src/data/saver.ts @@ -0,0 +1,36 @@ +import { FormModelState } from "../store/formState"; +import { ModelState } from "../store/models"; +import { getModelNamesSelector, getModelReadSelector, getModelWriteActionCreator, StoreType } from "./data"; + +export class FormStateSaver { + private saveModel: (name: string, value: FormModelState) => void + + constructor() { + this.saveModel = getModelWriteActionCreator(StoreType.FormState); + } + + save = (state: any): void => { + let fmns = getModelNamesSelector(StoreType.FormState)(); + let formModelNames = fmns(state); + let fmvs = getModelReadSelector(StoreType.FormState); + let mvs = getModelReadSelector(StoreType.Models); + + let formModelValues = Object.fromEntries(formModelNames.map(mn => { + return [ + mn, + fmvs(mn)(state) + ] + })) + + let modelValues = Object.fromEntries(formModelNames.map(mn => { + return [ + mn, + mvs(mn)(state) + ] + })) + + let modelUpdated = Object.entries(formModelValues).map(([modelName, formModelValue]) => { + + }) + } +} diff --git a/react/src/data/wrapper.ts b/react/src/data/wrapper.ts deleted file mode 100644 index eca518937b..0000000000 --- a/react/src/data/wrapper.ts +++ /dev/null @@ -1,243 +0,0 @@ -import React, { Dispatch } from "react"; -import { useDispatch, useSelector } from "react-redux"; -import { AnyAction } from "redux"; -import { ArrayModelElement } from "../layout/input/array"; -import { FormActions, FormFieldState, FormModelState, FormSelectors } from "../store/formState"; -import { ModelActions, ModelSelectors, ModelState } from "../store/models"; - -export abstract class AbstractModelsWrapper { - abstract getModel(modelName: string, state: any): M; - abstract hookModel(modelName: string): M; - abstract updateModel(modelName: string, value: M, state: any): void; - abstract getFieldFromModel(fieldName: string, model: M): F; - abstract setFieldInModel(fieldName: string, model: M, value: F): M; - - getArraySubField = (fieldName: string, index: number, subFieldName: string, model: M): F => { - return this.getFieldFromModel(subFieldName, this.getArrayFieldAtIndex(fieldName, index, model).item); - } - - setArraySubField = (fieldName: string, index: number, subFieldName: string, model: M, value: F): M => { - let af = this.getArrayFieldAtIndex(fieldName, index, model); - let nm = this.setFieldInModel(subFieldName, af.item, value); - return this.setArrayFieldAtIndex(fieldName, index, model, { - item: nm, - model: af.model - }); - } - - getArrayFieldAtIndex = (fieldName: string, index: number, model: M): ArrayModelElement => { - let fieldState = this.getFieldFromModel(fieldName, model); - let len = this.getArrayFieldLength(fieldState); - if(index >= len) { - //throw new Error(`index=${index} of out bounds=${len}`); - return undefined; - } - - return fieldState[index]; - } - - setArrayFieldAtIndex = (fieldName: string, index: number, model: M, value: ArrayModelElement): M => { - let fieldState = this.getFieldFromModel(fieldName, model); - let len = this.getArrayFieldLength(fieldState); - if(index >= len) { - //throw new Error(`index=${index} of out bounds=${len}`); - return undefined; - } - - // TODO: cant change types of model - let nv = [...(fieldState as any)]; - console.log("value", value); - nv[index] = value; - console.log("nv", nv); - return this.setFieldInModel(fieldName, model, nv as F); - } - - getArrayFieldLength = (field: F): number => { - return ((field as any[]) || []).length; - } - - updateField = (fieldName: string, modelName: string, state: any, value: F): void => { - let model = this.getModel(modelName, state); - model = this.setFieldInModel(fieldName, model, value); - this.updateModel(modelName, model, state); - } -} - -export const CFormStateWrapper = React.createContext>>(undefined); -export const CModelsWrapper = React.createContext>(undefined); - -export function getModelValues(modelNames: string[], modelsWrapper: AbstractModelsWrapper, state: any): {[modelName: string]: M} { - return Object.fromEntries(modelNames.map(mn => [mn, modelsWrapper.getModel(mn, state)])); -} - -export class FormStateWrapper extends AbstractModelsWrapper> { - formActions: FormActions; - formSelectors: FormSelectors; - dispatch: Dispatch; - constructor({ formActions, formSelectors }: { formActions: FormActions, formSelectors: FormSelectors }) { - super(); - this.formActions = formActions; - this.formSelectors = formSelectors; - - let dispatchFn = useDispatch; - this.dispatch = dispatchFn(); - } - - override getModel = (modelName: string, state: any) => { - return this.formSelectors.selectFormState(modelName)(state); - } - - override updateModel = (modelName: string, value: any, state: any) => { - //console.log("dispatching update form to ", modelName, " changing to value ", value); - this.dispatch(this.formActions.updateFormState({ - name: modelName, - value - })) - } - - override hookModel = (modelName: string) => { - let m = useSelector(this.formSelectors.selectFormState(modelName)); - if(m === undefined || m === null) { - throw new Error("model could not be hooked because it was not found: " + modelName); - } - return m; - } - - getFieldFromModel(fieldName: string, model: FormModelState): FormFieldState { - let fv = model[fieldName]; - if(fv === undefined || fv === null) { - throw new Error(`field could not be found in model state: ${fieldName}, ${JSON.stringify(model)}`) - } - return fv; - } - - setFieldInModel(fieldName: string, model: FormModelState, value: FormFieldState): FormModelState { - let m = {...model}; - m[fieldName] = value; - return m; - } -} - -export class ModelsWrapper extends AbstractModelsWrapper { - modelActions: ModelActions; - modelSelectors: ModelSelectors; - dispatch: Dispatch; - - constructor({ modelActions, modelSelectors }: { modelActions: ModelActions, modelSelectors: ModelSelectors }) { - super(); - this.modelActions = modelActions; - this.modelSelectors = modelSelectors; - - let dispatchFn = useDispatch; - this.dispatch = dispatchFn(); - } - - getModel = (modelName: string, state: any) => { - return this.modelSelectors.selectModel(modelName)(state); - } - - getModelNames = (state: any): string[] => { - return this.modelSelectors.selectModelNames()(state); - } - - updateModel = (modelName: string, value: ModelState, state: any) => { - //console.log("dispatching update to ", modelName, " changing to value ", value); - this.dispatch(this.modelActions.updateModel({ - name: modelName, - value - })) - } - - hookModel = (modelName: string) => { - let m = useSelector(this.modelSelectors.selectModel(modelName)); - if(m === undefined || m === null) { - throw new Error("model could not be hooked because it was not found: " + modelName); - } - return m; - } - - getFieldFromModel(fieldName: string, model: ModelState): unknown { - let fv = model[fieldName]; - if(fv === undefined || fv === null) { - throw new Error(`field could not be found in model state: ${fieldName}, ${JSON.stringify(model)}`) - } - return fv; - } - - setFieldInModel(fieldName: string, model: ModelState, value: unknown): ModelState { - let m = {...model}; - m[fieldName] = value; - return m; - } - - // TODO: this should not be housed here, need separate abstraction to communicate to server, should just return formatted models - saveToServer = (simulationInfo: any, modelNames: string[], state: any) => { - let models = Object.fromEntries(modelNames.map(mn => [mn, this.getModel(mn, state)])); - simulationInfo.models = models; - fetch("/save-simulation", { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(simulationInfo) - }).then(resp => { - // TODO: error handling - }) - } -} - - -export type ModelHandle = { - getModel(modelName: string, state: any): M, - hookModel(modelName: string): M, - updateModel(modelName: string, value: M, state: any): void -} - -/** - * Fake -> real - */ -export type ModelAliases = { - [fake: string]: { - handle: ModelHandle, - realSchemaName: string - } -} - -export class ModelsWrapperWithAliases extends AbstractModelsWrapper { - constructor(private parent: AbstractModelsWrapper, private aliases: ModelAliases) { - super(); - - this['getModelNames'] = parent['getModelNames'] - this['saveToServer'] = parent['saveToServer'] - } - - private getAliasedHandle(modelName: string): ModelHandle | undefined { - if(modelName in this.aliases) { - return this.aliases[modelName].handle; - } - return undefined; - } - - getModel(modelName: string, state: any): M { - return (this.getAliasedHandle(modelName) || this.parent).getModel(modelName, state); - } - - hookModel(modelName: string): M { - return (this.getAliasedHandle(modelName) || this.parent).hookModel(modelName); - } - - updateModel(modelName: string, value: M, state: any): void { - return (this.getAliasedHandle(modelName) || this.parent).updateModel(modelName, value, state); - } - - getFieldFromModel(fieldName: string, model: M): F { - return this.parent.getFieldFromModel(fieldName, model); - } - - setFieldInModel(fieldName: string, model: M, value: F): M { - return this.parent.setFieldInModel(fieldName, model, value); - } -} - - - diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 14bd1f44ff..cc14564540 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -94,6 +94,7 @@ export class BeamlineLayout extends Layout { } component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { + console.log("RENDER BEAMLINE"); let routeHelper = useContext(CRouteHelper); let formStateWrapper = useContext(CFormStateWrapper); let modelsWrapper = useContext(CModelsWrapper); @@ -111,11 +112,12 @@ export class BeamlineLayout extends Layout { let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; let addBeamlineElement = (element: BeamlineElement) => { + console.log("AAA"); let ms = schema.models[element.model]; // TODO: use generic methods let prev: FormModelState | undefined = beamlineValue.length > 0 ? beamlineValue[beamlineValue.length - 1].item : undefined - let nextPosition: number = prev ? prev.position.value + 5 : 0; - let nextId: number = prev ? prev.id.value + 1 : 1; + let nextPosition: string = prev ? `${parseFloat(prev.position.value) + 5}` : "0"; + let nextId: string = prev ? `${parseInt(prev.id.value) + 1}` : "1"; let mv = formStateFromModel({ id: nextId, position: nextPosition, @@ -147,10 +149,13 @@ export class BeamlineLayout extends Layout { return r[0]; } + console.log("MAPPING BEAMLINE ELEMENTS"); + let beamlineComponents = beamlineValue.map((e, i) => { let model = e.model; let ele: FormModelState = e.item; let id = ele.id.value; + console.log("id", id); let baseElement = findBaseElementByModel(model); let deps = baseElement.layouts.flatMap(l => l.getFormDependencies()); let aliases: FormControllerAliases = [ @@ -165,13 +170,11 @@ export class BeamlineLayout extends Layout { } ]; return ( - - - - updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> - - - + + + updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> + + ) }) @@ -182,7 +185,7 @@ export class BeamlineLayout extends Layout { let actionButtons = return ( - <> +
{elementThumbnails}
@@ -205,7 +208,7 @@ export class BeamlineLayout extends Layout { {isDirty && actionButtons}
- +
) } } diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index d395c2f6b8..1316e255d6 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -198,7 +198,13 @@ export function arrayPositionHandle(modelsWrapper: AbstractModelsWrapper { let m = modelsWrapper.hookModel(realArrayDep.modelName); - return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; + console.log("handle hookModel"); + console.log("m", m); + console.log("real field name", realArrayDep.fieldName); + console.log("index in array", arrayIndex); + let af = modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; + console.log("af", af); + return af; } } return handle; @@ -236,13 +242,18 @@ export function AliasedFormControllerWrapper(props: { aliases: FormControllerAli let nModelsWrapper = new ModelsWrapperWithAliases(modelsWrapper, aliasesForWrapper(modelsWrapper, aliases)); let nFormStateWrapper = new ModelsWrapperWithAliases(formStateWrapper, aliasesForWrapper(formStateWrapper, aliases)); + // i dont know why but the div is required!! for updates to work correctly + // https://stackoverflow.com/questions/54880669/react-domexception-failed-to-execute-removechild-on-node-the-node-to-be-re return ( - - - - {props.children} - - - +
+ + + + {props.children} + + + +
+ ) } diff --git a/react/src/layout/input/array.tsx b/react/src/layout/input/array.tsx index 5b060a4697..f8ff56e901 100644 --- a/react/src/layout/input/array.tsx +++ b/react/src/layout/input/array.tsx @@ -1,12 +1,5 @@ import { InputConfigBase, InputLayout } from "./input"; -export type ArrayModelElement = { - item: T, - model: string -} - -export type ArrayField = ArrayModelElement[] - export type ArrayInputConfig = { } & InputConfigBase diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index fbb8402707..11bc1b7e16 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -70,7 +70,7 @@ export class AutoRunReportLayout extends Layout { useEffect(() => { updateSimulationData(undefined); let pollingVersion = uuidv4(); - simulationPollingVersionRef.current = pollingVersion; + //simulationPollingVersionRef.current = pollingVersion; simulationInfoPromise.then(({ models, simulationId, simulationType, version }) => { updateModel(models[report]); pollRunReport(routeHelper, { @@ -81,11 +81,11 @@ export class AutoRunReportLayout extends Layout { forceRun: false, callback: (simulationData) => { // guard concurrency - if(simulationPollingVersionRef.current === pollingVersion) { - updateSimulationData(simulationData); - } else { - console.log("polling data was not from newest request"); - } + //if(simulationPollingVersionRef.current === pollingVersion) { + updateSimulationData(simulationData); + //} else { + // console.log("polling data was not from newest request"); + //} } }) }) diff --git a/react/src/store/common.ts b/react/src/store/common.ts new file mode 100644 index 0000000000..365ba91125 --- /dev/null +++ b/react/src/store/common.ts @@ -0,0 +1,64 @@ +import { ActionCreatorWithPayload, createSlice, Slice } from "@reduxjs/toolkit"; + +export type ModelStateUpdate = { + name: string, + value: V +} + +export type ModelSelector = (name: string) => (state: any) => V; + +export type ModelWriteActionCreator = ActionCreatorWithPayload, string>; + +export type ArrayFieldElement = { + model: string, + item: V +} + +export type ArrayFieldState = ArrayFieldElement[] + +export type StoreActions = { + updateModel: ModelWriteActionCreator; +} + +export type StoreSelectors = { + selectModel: ModelSelector, + selectModelNames: () => ((state: any) => string[]) +} + +export type StoreState = { + [key: string]: M +} + +export const makeSlice = (name: string): { + slice: Slice>, + actions: StoreActions, + selectors: StoreSelectors +} => { + let slice: Slice> = createSlice({ + name, + initialState: {}, + reducers: { + updateFormState: (state, {payload: {name, value}}: {payload: ModelStateUpdate}) => { + (state[name] as any) = value; + } + } + }); + + let selectors: StoreSelectors = { + selectModel: (name: string) => (state) => state[slice.name][name], + selectModelNames: () => { + return (state: any) => Object.keys(state[slice.name]); + } + } + + let { updateModel } = slice.actions; + let actions: StoreActions = { + updateModel + } + + return { + slice, + actions, + selectors + } +} diff --git a/react/src/store/formState.ts b/react/src/store/formState.ts index 719558968f..b4d001c0f1 100644 --- a/react/src/store/formState.ts +++ b/react/src/store/formState.ts @@ -1,8 +1,8 @@ -import { ActionCreatorWithPayload, createSlice, Slice } from '@reduxjs/toolkit'; +import { ArrayFieldState, makeSlice } from "./common" export type FormFieldState = { valid: boolean, - value: T, + value: T | ArrayFieldState, touched: boolean, active: boolean } @@ -11,36 +11,8 @@ export type FormModelState = { [fieldName: string]: FormFieldState } -export type FormStateUpdate = { - name: string, // TODO rename to modelName - value: FormModelState -} - -export let formStatesSlice: Slice<{ - [modelName: string]: FormModelState -}> = createSlice({ - name: 'formStates', - initialState: {}, - reducers: { - updateFormState: (state, {payload: {name, value}}: {payload: FormStateUpdate}) => { - state[name] = value; - } - } -}); - -export type FormSelectors = { - selectFormState: (name: string) => ((state: any) => FormModelState) -} - -export let formSelectors: FormSelectors = { - selectFormState: (name: string) => (state) => state[formStatesSlice.name][name] -} - -let { updateFormState } = formStatesSlice.actions; - -export type FormActions = { - updateFormState: ActionCreatorWithPayload, -} -export let formActions: FormActions = { - updateFormState -} +export const { + slice: formStatesSlice, + actions: formActions, + selectors: formSelectors +} = makeSlice("formState"); diff --git a/react/src/store/models.ts b/react/src/store/models.ts index 3efa3a00fa..b4e624752c 100644 --- a/react/src/store/models.ts +++ b/react/src/store/models.ts @@ -1,44 +1,11 @@ -import { ActionCreatorWithPayload, createSlice, Slice } from '@reduxjs/toolkit'; +import { ArrayFieldState, makeSlice } from './common'; export type ModelState = { - [fieldName: string]: unknown + [fieldName: string]: unknown | ArrayFieldState } -export type ModelStateUpdate = { - name: string, // TODO rename to modelName - value: ModelState -} - -export type ModelStates = {[modelName: string]: ModelState} - -export const modelsSlice: Slice = createSlice({ - name: 'modelsSlice', - initialState: {}, - reducers: { - updateModel: (state, {payload: {name, value}}: { payload: ModelStateUpdate }) => { - state[name] = value; - }, - } -}); - -let { updateModel } = modelsSlice.actions; - -export type ModelActions = { - updateModel: ActionCreatorWithPayload -} -export let modelActions: ModelActions = { - updateModel -} - -export type ModelSelectors = { - selectModel: (name: string) => ((state: any) => ModelState), - selectModelNames: () => ((state: any) => string[]) -} -export let modelSelectors: ModelSelectors = { - selectModel: (name: string) => { - return (state: any) => state[modelsSlice.name][name]; - }, - selectModelNames: () => { - return (state: any) => Object.keys(state[modelsSlice.name]); - } -} +export const { + slice: modelsSlice, + actions: modelActions, + selectors: modelSelectors +} = makeSlice("models"); diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 5c866dac18..60dddeda29 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -1,14 +1,6 @@ -import { ModelsAccessor } from "../data/accessor"; +import { getValueSelector, StoreType } from "../data/data"; import { Dependency } from "../data/dependency"; -import { AbstractModelsWrapper } from "../data/wrapper"; -import { FormFieldState } from "../store/formState"; - -export type ValueSelector = (v: T) => any; - -export const ValueSelectors = { - Models: (v: any) => v, - Fields: (v: FormFieldState) => v.value -} +import { HandleFactory } from "../data/handle"; function getStringReplacementPatterns(str: string): RegExpMatchArray[] { return [...str.matchAll(/\$\(([^\%]+?)\)/g)]; @@ -44,7 +36,9 @@ export class InterpolationBase { ) } - withDependencies(modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector): InterpolationResult { + withDependencies(handleFactory: HandleFactory, type: StoreType): InterpolationResult { + let valueSelector = getValueSelector(type) as (v: F) => any; + let mappingsArr = this.matches.map(([originalString, mappedGroup]) => { return { original: originalString, @@ -52,12 +46,10 @@ export class InterpolationBase { } }); - let modelAccessor = new ModelsAccessor(modelsWrapper, mappingsArr.map(v => v.dependency)); - let valuesArr = mappingsArr.map(mapping => { return { ...mapping, - value: (valueSelector)(modelAccessor.getFieldValue(mapping.dependency)) + value: (valueSelector)(handleFactory.createHandle(mapping.dependency, type).hook().value) } }) From aa971431cca5435429cf950fa2dd5c2c60464cf9 Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 31 Mar 2023 19:37:04 +0000 Subject: [PATCH 20/68] wip refactor data --- react/src/component/app.tsx | 23 ++--- react/src/component/simulation.tsx | 45 ++++++--- react/src/data/data.ts | 6 +- react/src/data/handle.ts | 3 + react/src/data/report.ts | 9 +- react/src/data/saver.ts | 126 ++++++++++++++++++------ react/src/hook/shown.ts | 11 ++- react/src/layout/form.tsx | 152 ++++++++--------------------- react/src/layout/panel.tsx | 8 +- 9 files changed, 195 insertions(+), 188 deletions(-) diff --git a/react/src/component/app.tsx b/react/src/component/app.tsx index 9dfccc0926..a2a10ff295 100644 --- a/react/src/component/app.tsx +++ b/react/src/component/app.tsx @@ -14,12 +14,7 @@ import { CRouteHelper, RouteHelper } from "../utility/route"; import { getAppCombinedSchema } from "../utility/schema"; export const AppContextWrapper = (props) => { - const modelsStore = configureStore({ // TODO: this belongs on the simulation root component - reducer: { - [modelsSlice.name]: modelsSlice.reducer, - [formStatesSlice.name]: formStatesSlice.reducer, - }, - }); + let appName = useContext(CAppName); const [hasAppSchema, schema] = useSetup(true, getAppCombinedSchema(appName)); @@ -27,15 +22,13 @@ export const AppContextWrapper = (props) => { const routeHelper = new RouteHelper(appName, schema); let appWrapper = new AppWrapper(appName, routeHelper); return ( - - - - - {props.children} - - - - + + + + {props.children} + + + ) } return undefined; diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index dcc3cbae81..03c5fbca97 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -11,7 +11,8 @@ import React, { import { modelSelectors, modelActions, - ModelState + ModelState, + modelsSlice } from "../store/models"; import { FormStateInitializer } from "./reusable/form"; import { useNavigate, useResolvedPath } from "react-router-dom"; @@ -27,8 +28,12 @@ import * as Icon from "@fortawesome/free-solid-svg-icons"; import { useSetup } from "../hook/setup"; import { Portal } from "./reusable/portal"; import { downloadAs, getAttachmentFileName } from "../utility/download"; -import { useStore } from "react-redux"; +import { Provider, useDispatch } from "react-redux"; import { StoreState } from "../store/common"; +import { configureStore } from "@reduxjs/toolkit"; +import { formStatesSlice } from "../store/formState"; +import { BaseHandleFactory, CHandleFactory } from "../data/handle"; +import { StoreType } from "../data/data"; export type SimulationInfoRaw = { models: StoreState, @@ -43,11 +48,18 @@ export type SimulationInfo = SimulationInfoRaw & { function SimulationInfoInitializer(props: { simulationId: string } & {[key: string]: any}) { let { simulationId } = props; + const modelsStore = configureStore({ // TODO: this belongs on the simulation root component + reducer: { + [modelsSlice.name]: modelsSlice.reducer, + [formStatesSlice.name]: formStatesSlice.reducer, + }, + }); + let [simulationInfoPromise, updateSimulationInfoPromise] = useState(undefined); let [hasInit, updateHasInit] = useState(false); let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); - let store = useStore(); + let dispatch = useDispatch(); useEffect(() => { updateSimulationInfoPromise(new Promise((resolve, reject) => { @@ -58,12 +70,14 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri })).then(async (resp) => { let simulationInfo = await resp.json(); let models = simulationInfo['models'] as ModelState[]; - console.log("models", models); for(let [modelName, model] of Object.entries(models)) { - modelsWrapper.updateModel(modelName, model, store.getState()); + dispatch(modelActions.updateModel({ + name: modelName, + value: model + })) } - + resolve({...simulationInfo, simulationId}); updateHasInit(true); }) @@ -71,11 +85,13 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri }, []) return hasInit && simulationInfoPromise && ( - - - {props.children} - - + + + + {props.children} + + + ) } @@ -238,12 +254,11 @@ export function SimulationOuter(props) { let pathPrefix = useResolvedPath(''); let currentRelativeRouter = new RelativeRouteHelper(pathPrefix); - let modelsWrapper = useContext(CModelsWrapper); - let simNameDep = new Dependency("simulation.name"); - let simNameAccessor = new ModelsAccessor(modelsWrapper, [simNameDep]); + let handleFactory = useContext(CHandleFactory); + let simNameHandle = handleFactory.createHandle(new Dependency("simulation.name"), StoreType.Models).hook(); useEffect(() => { - document.title = simNameAccessor.getFieldValue(simNameDep) as string; + document.title = simNameHandle.value as string; }) // TODO: navbar should route to home, when one is made diff --git a/react/src/data/data.ts b/react/src/data/data.ts index 3d00b7ad20..bd2dab90f6 100644 --- a/react/src/data/data.ts +++ b/react/src/data/data.ts @@ -14,7 +14,7 @@ export const getModelWriteActionCreator = (type: StoreType) => { let mac = (type === StoreType.Models ? modelActions.updateModel : formActions.updateModel) as ModelWriteActionCreator; return (name: string, value: V) => mac({ name, value }); } -export const getModelNamesSelector = (type: StoreType) => { +export const getModelNamesSelector = (type: StoreType) => { return (type === StoreType.Models ? modelSelectors.selectModelNames : formSelectors.selectModelNames); } @@ -22,9 +22,9 @@ export type ValueSelector = (v: T) => any; export const ValueSelectors = { Models: (v: any) => v, - Fields: (v: FormFieldState) => v.value + Form: (v: FormFieldState) => v.value } export const getValueSelector = (storeType: StoreType): ((v: any) => any) | ((v: FormFieldState) => unknown) => { - return storeType === StoreType.Models ? ValueSelectors.Models : ValueSelectors.Fields; + return storeType === StoreType.Models ? ValueSelectors.Models : ValueSelectors.Form; } diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 0572c688aa..3b617ea06d 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -1,8 +1,11 @@ +import React from "react"; import { useSelector } from "react-redux"; import { AnyAction, Dispatch } from "redux"; import { ArrayFieldElement, ArrayFieldState } from "../store/common"; import { getModelReadSelector, getModelWriteActionCreator, StoreType } from "./data"; +export const CHandleFactory = React.createContext(undefined); + export abstract class DataHandle { constructor(protected currentValue: V) { this.value = currentValue; diff --git a/react/src/data/report.ts b/react/src/data/report.ts index 3fa82de35d..725e1d242e 100644 --- a/react/src/data/report.ts +++ b/react/src/data/report.ts @@ -1,9 +1,10 @@ import { getSimulationFrame, pollRunReport, ResponseHasState, getRunStatusOnce } from "../utility/compute"; import { v4 as uuidv4 } from 'uuid'; import React from "react"; -import { ModelStates } from "../store/models"; +import { ModelState } from "../store/models"; import { mapProperties } from "../utility/object"; import { RouteHelper } from "../utility/route"; +import { StoreState } from "../store/common"; export const CReportEventManager = React.createContext(undefined); @@ -24,7 +25,7 @@ export type ReportEventSubscriber = { type RunStatusParams = { appName: string, - models: ModelStates, + models: StoreState, simulationId: string, report: string } @@ -91,7 +92,7 @@ export class ReportEventManager { report }: { appName: string, - models: ModelStates, + models: StoreState, simulationId: string, report: string }) => { @@ -114,7 +115,7 @@ export class ReportEventManager { report }: { appName: string, - models: ModelStates, + models: StoreState, simulationId: string, report: string }) => { diff --git a/react/src/data/saver.ts b/react/src/data/saver.ts index 683e912ecb..b0fd1fad17 100644 --- a/react/src/data/saver.ts +++ b/react/src/data/saver.ts @@ -1,36 +1,106 @@ -import { FormModelState } from "../store/formState"; -import { ModelState } from "../store/models"; -import { getModelNamesSelector, getModelReadSelector, getModelWriteActionCreator, StoreType } from "./data"; +import { Dispatch, AnyAction } from "redux"; +import { ArrayFieldElement, ArrayFieldState } from "../store/common"; +import { Schema } from "../utility/schema"; +import { StoreType } from "./data"; +import { ArrayDataHandle, BaseHandleFactory, DataHandle, EmptyDataHandle } from "./handle"; -export class FormStateSaver { - private saveModel: (name: string, value: FormModelState) => void +type SaveFunc = (state: any, dispatch: Dispatch) => void - constructor() { - this.saveModel = getModelWriteActionCreator(StoreType.FormState); +type SaveFuncKeyPair = { + key: any, + saveFn: SaveFunc +} + +export class FormStateHandleFactory extends BaseHandleFactory { + private updated: SaveFuncKeyPair[] = [] + + constructor(private schema: Schema) { + super(); } - save = (state: any): void => { - let fmns = getModelNamesSelector(StoreType.FormState)(); - let formModelNames = fmns(state); - let fmvs = getModelReadSelector(StoreType.FormState); - let mvs = getModelReadSelector(StoreType.Models); - - let formModelValues = Object.fromEntries(formModelNames.map(mn => { - return [ - mn, - fmvs(mn)(state) - ] - })) - - let modelValues = Object.fromEntries(formModelNames.map(mn => { - return [ - mn, - mvs(mn)(state) - ] - })) - - let modelUpdated = Object.entries(formModelValues).map(([modelName, formModelValue]) => { + private emptyDataHandleFor>(parent: EmptyDataHandle, updateCallback: (dh: D) => void): EmptyDataHandle { + return new (class implements EmptyDataHandle { + private dataHandleFor(parent: DataHandle): D { + let dh = new (class extends ArrayDataHandle { + append(element: ArrayFieldElement, dispatch: Dispatch) { + (parent as ArrayDataHandle).append(element, dispatch); + updateCallback(dh); + } + appendAt(index: number, element: ArrayFieldElement, dispatch: Dispatch) { + (parent as ArrayDataHandle).appendAt(index, element, dispatch); + updateCallback(dh); + } + removeAt(index: number, dispatch: Dispatch) { + (parent as ArrayDataHandle).removeAt(index, dispatch); + updateCallback(dh); + } + write = (value: V, dispatch: Dispatch) => { + parent.write(value, dispatch); + updateCallback(dh); + } + })(parent.value) as any as D; + return dh; + } + + initialize(state: any): D { + return this.dataHandleFor(parent.initialize(state)); + } + hook(): D { + return this.dataHandleFor(parent.hook()); + } + })(); + } + + private addToUpdated = (key: any, saveFn: SaveFunc) => { + let idx = this.updated.findIndex(u => u.key === key); + if(idx >= 0) { + this.updated.splice(idx, 1); + } + this.updated.push({ + key, + saveFn }) } + + save(state: any, dispatch: Dispatch) { + this.updated.forEach(u => u.saveFn(state, dispatch)); + this.updated = []; + } + + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + let edh = super.createHandle(dependency, type); + if(type === StoreType.FormState) { + return this.emptyDataHandleFor>(edh, (dh: DataHandle) => { + this.addToUpdated( + dh, + (state: any, dispatch: Dispatch) => { + let f = super.createHandle(dependency, StoreType.FormState).initialize(state); + let m = super.createHandle(dependency, StoreType.Models).initialize(state); + let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f.value); + m.write(v, dispatch); + } + ); + }) + } + return edh; + } + + createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { + let edh = super.createArrayHandle(dependency, type); + if(type === StoreType.FormState) { + return this.emptyDataHandleFor>(edh, (dh: ArrayDataHandle) => { + this.addToUpdated( + dh, + (state: any, dispatch: Dispatch) => { + let f = super.createArrayHandle(dependency, StoreType.FormState).initialize(state); + let m = super.createArrayHandle(dependency, StoreType.Models).initialize(state); + let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f.value); + m.write(v, dispatch); + } + ); + }) + } + return edh; + } } diff --git a/react/src/hook/shown.ts b/react/src/hook/shown.ts index 30a78bc844..f2e9fa51a7 100644 --- a/react/src/hook/shown.ts +++ b/react/src/hook/shown.ts @@ -1,9 +1,12 @@ -import { AbstractModelsWrapper } from "../data/wrapper"; -import { interpolate, ValueSelector } from "../utility/string" +import { useContext } from "react"; +import { StoreType } from "../data/data"; +import { CHandleFactory } from "../data/handle"; +import { interpolate } from "../utility/string" -export function useShown(shownStr: string, defaultValue: boolean, modelsWrapper: AbstractModelsWrapper, valueSelector: ValueSelector) { +export function useShown(shownStr: string, defaultValue: boolean, type: StoreType) { + let dhf = useContext(CHandleFactory); if(shownStr) { - let shown = interpolate(shownStr).withDependencies(modelsWrapper, valueSelector).evaluated(); + let shown = interpolate(shownStr).withDependencies(dhf, type).evaluated(); if(typeof(shown) !== 'boolean'){ throw new Error(`'shown' function did not evaluate to a boolean "${shownStr}" -> ${shown}`) } diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index 1316e255d6..a797b51f8e 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -8,24 +8,24 @@ import { } from "react-bootstrap"; import { Dependency } from "../data/dependency"; import { FieldInput, LabeledFieldInput } from "../component/reusable/input"; -import { CFormController, fieldStateFromValue, FormController } from "../data/formController"; import { useShown } from "../hook/shown"; -import { CModelsWrapper, CFormStateWrapper, ModelsWrapperWithAliases, AbstractModelsWrapper, ModelAliases, ModelHandle } from "../data/wrapper"; -import { useStore } from "react-redux"; +import { useDispatch, useStore } from "react-redux"; import { CSchema } from "../data/appwrapper"; -import { ValueSelectors } from "../utility/string"; import { Schema } from "../utility/schema"; +import { FormStateHandleFactory } from "../data/saver"; +import { CHandleFactory } from "../data/handle"; +import { StoreType } from "../data/data"; +import { FormFieldState } from "../store/formState"; -export function FormControllerElement(props: {children?: React.ReactNode, dependencies: Dependency[]}) { - let formState = useContext(CFormStateWrapper); +export function FormControllerElement(props: {children?: React.ReactNode}) { let schema = useContext(CSchema); - let modelsWrapper = useContext(CModelsWrapper); - let formController = new FormController(formState, modelsWrapper, props.dependencies, schema); + let formHandleFactory = new FormStateHandleFactory(schema); + // TODO: form controller might need to "subscribe to updates" during save return ( - + { props.children } - + ) } @@ -39,7 +39,7 @@ export function LayoutWithFormController(Child: LayoutType): LayoutT this.component = (props) => { let ChildComponent = childComponent; return ( - + ) @@ -71,11 +71,10 @@ export class FieldGridLayout extends Layout { } component = (props: LayoutProps<{}>) => { - let formController = useContext(CFormController); - let formState = useContext(CFormStateWrapper); + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let schema = useContext(CSchema); - let store = useStore(); - let gridShown = useShown(this.config.shown, true, formState, ValueSelectors.Fields); + let dispatch = useDispatch(); + let gridShown = useShown(this.config.shown, true, StoreType.FormState); if (! gridShown) { return <> @@ -96,27 +95,28 @@ export class FieldGridLayout extends Layout { for(let idx = 0; idx < rows.length; idx++) { let row = rows[idx]; - let shown = useShown(row.shown, true, formState, ValueSelectors.Fields); + let shown = useShown(row.shown, true, StoreType.FormState); let fields = row.fields; let labelElement = someRowHasLabel ? ({row.label || ""}) : undefined; let rowElement = shown ? ( {labelElement ? {labelElement} : undefined} {columns.map((_, index) => { - let fieldDepString = fields[index]; - let fieldDependency = new Dependency(fieldDepString); - let fieldValue = formController.getFormStateAccessor().getFieldValue(fieldDependency); + let fieldDependency = new Dependency(fields[index]); + let fieldHandle = formHandleFactory.createHandle>(fieldDependency, StoreType.FormState).hook(); let fieldType = schema.models[fieldDependency.modelName][fieldDependency.fieldName].type; + let active = fieldHandle.value?.active !== undefined ? fieldHandle.value.active : true; return ( { - formState.updateField( - fieldDependency.fieldName, - fieldDependency.modelName, - store.getState(), - fieldStateFromValue(value, fieldValue, fieldType)); + fieldHandle.write({ + valid: fieldType.validate(value), + touched: true, + value, + active + }, dispatch) }} dependency={fieldDependency} inputComponent={fieldType.component}/> @@ -145,33 +145,35 @@ export class FieldListLayout extends Layout { } component = (props: LayoutProps<{}>) => { - let formController = useContext(CFormController); - let formState = useContext(CFormStateWrapper); + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let schema = useContext(CSchema); - let store = useStore(); + let dispatch = useDispatch(); let fields = this.config.fields; return <> {fields.map((fieldDepString, idx) => { let fieldDep = new Dependency(fieldDepString); - let fieldValue = formController.getFormStateAccessor().getFieldValue(fieldDep); + let fieldHandle = formHandleFactory.createHandle>(fieldDep, StoreType.FormState).hook(); + let fieldType = schema.models[fieldDep.modelName][fieldDep.fieldName].type; + let active = fieldHandle.value?.active !== undefined ? fieldHandle.value.active : true; let fieldSchema = schema.models[fieldDep.modelName][fieldDep.fieldName]; - let shown = useShown(fieldSchema.shown, true, formState, ValueSelectors.Fields); + let shown = useShown(fieldSchema.shown, true, StoreType.FormState); - if(shown && fieldValue.active) { + if(shown && active) { return { - formState.updateField( - fieldDep.fieldName, - fieldDep.modelName, - store.getState(), - fieldStateFromValue(value, fieldValue, fieldSchema.type)); + fieldHandle.write({ + valid: fieldType.validate(value), + touched: true, + value, + active + }, dispatch) }} inputComponent={fieldSchema.type.component}/> } @@ -181,79 +183,3 @@ export class FieldListLayout extends Layout { } } - -export function arrayPositionHandle(modelsWrapper: AbstractModelsWrapper, realArrayDep: Dependency, arrayIndex: number): ModelHandle { - let handle: ModelHandle = { - updateModel: (modelName: string, value: M, state: any) => { - let m = modelsWrapper.getModel(realArrayDep.modelName, state); - let nm = modelsWrapper.setArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m, { - model: modelName, - item: value - }); - modelsWrapper.updateModel(realArrayDep.modelName, nm, state); - }, - getModel: (_: string, state: any): M => { - let m = modelsWrapper.getModel(realArrayDep.modelName, state); - return modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; - }, - hookModel: (_: string): M => { - let m = modelsWrapper.hookModel(realArrayDep.modelName); - console.log("handle hookModel"); - console.log("m", m); - console.log("real field name", realArrayDep.fieldName); - console.log("index in array", arrayIndex); - let af = modelsWrapper.getArrayFieldAtIndex(realArrayDep.fieldName, arrayIndex, m)?.item; - console.log("af", af); - return af; - } - } - return handle; -} - -export type FormControllerAliases = { real: { modelName: string, fieldName: string, index: number }, fake: string, realSchemaName: string }[] -export function AliasedFormControllerWrapper(props: { aliases: FormControllerAliases, children?: React.ReactNode }) { - let { aliases } = props; - - let schema = useContext(CSchema); - let modelsWrapper = useContext(CModelsWrapper); - let formStateWrapper = useContext(CFormStateWrapper); - - let nSchema: Schema = {...schema}; - - - for(let alias of aliases) { - nSchema.models[alias.fake] = nSchema.models[alias.realSchemaName]; - } - - function aliasesForWrapper(wrapper: AbstractModelsWrapper, aliases: FormControllerAliases): ModelAliases { - return Object.fromEntries( - aliases.map(alias => { - return [ - alias.fake, - { - handle: arrayPositionHandle(wrapper, new Dependency(`${alias.real.modelName}.${alias.real.fieldName}`), alias.real.index), - realSchemaName: alias.realSchemaName - } - ] - }) - ); - } - - let nModelsWrapper = new ModelsWrapperWithAliases(modelsWrapper, aliasesForWrapper(modelsWrapper, aliases)); - let nFormStateWrapper = new ModelsWrapperWithAliases(formStateWrapper, aliasesForWrapper(formStateWrapper, aliases)); - - // i dont know why but the div is required!! for updates to work correctly - // https://stackoverflow.com/questions/54880669/react-domexception-failed-to-execute-removechild-on-node-the-node-to-be-re - return ( -
- - - - {props.children} - - - -
- - ) -} diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 2894546e5a..eb6cc91b3f 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -1,12 +1,10 @@ import { useContext } from "react"; -import { interpolate, ValueSelectors } from "../utility/string"; +import { interpolate } from "../utility/string"; import { LayoutProps, Layout } from "./layout"; import { useStore } from "react-redux"; import { EditorPanel } from "../component/reusable/panel"; import "./panel.scss"; import React from "react"; -import { CFormController } from "../data/formController"; -import { CModelsWrapper, ModelsWrapper } from "../data/wrapper"; import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; @@ -34,8 +32,6 @@ export class PanelLayout extends Layout { } component = (props: LayoutProps<{}>) => { - let modelsWrapper = useContext(CModelsWrapper); - let formController = useContext(CFormController); let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); @@ -54,7 +50,7 @@ export class PanelLayout extends Layout { let modalChildren = (!!this.advanced) ? mapLayoutsToComponents(this.advanced) : undefined; let submit = () => { - formController.saveToModels(store.getState()); + //formController.saveToModels(store.getState()); simulationInfoPromise.then(simulationInfo => { (modelsWrapper as ModelsWrapper).saveToServer(simulationInfo, Object.keys(schema.models), store.getState()); }) From 38e2c1d23c1f82142c5e13f988bbd495595e526e Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 31 Mar 2023 19:45:08 +0000 Subject: [PATCH 21/68] wip refactor data --- react/src/data/appwrapper.ts | 15 ++++++++++++++- react/src/data/{saver.ts => form.ts} | 0 react/src/layout/form.tsx | 8 +++----- react/src/layout/panel.tsx | 15 ++++++++++----- 4 files changed, 27 insertions(+), 11 deletions(-) rename react/src/data/{saver.ts => form.ts} (100%) diff --git a/react/src/data/appwrapper.ts b/react/src/data/appwrapper.ts index 258bdb204c..113ae19c57 100644 --- a/react/src/data/appwrapper.ts +++ b/react/src/data/appwrapper.ts @@ -1,5 +1,7 @@ import React from "react" -import { SimulationInfo } from "../component/simulation" +import { SimulationInfo, SimulationInfoRaw } from "../component/simulation" +import { StoreState } from "../store/common" +import { ModelState } from "../store/models" import { RouteHelper } from "../utility/route" import { Schema } from "../utility/schema" @@ -105,4 +107,15 @@ export class AppWrapper { }) }).then(); } + + saveModelsToServer = (simulationInfo: SimulationInfoRaw, models: StoreState): Promise => { + simulationInfo.models = models; + return fetch("/save-simulation", { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(simulationInfo) + }) + } } diff --git a/react/src/data/saver.ts b/react/src/data/form.ts similarity index 100% rename from react/src/data/saver.ts rename to react/src/data/form.ts diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index a797b51f8e..b1ebb3ff5e 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -3,16 +3,14 @@ import React, { useContext } from "react"; import { Row, Col, - Form, - Container + Form } from "react-bootstrap"; import { Dependency } from "../data/dependency"; import { FieldInput, LabeledFieldInput } from "../component/reusable/input"; import { useShown } from "../hook/shown"; -import { useDispatch, useStore } from "react-redux"; +import { useDispatch } from "react-redux"; import { CSchema } from "../data/appwrapper"; -import { Schema } from "../utility/schema"; -import { FormStateHandleFactory } from "../data/saver"; +import { FormStateHandleFactory } from "../data/form"; import { CHandleFactory } from "../data/handle"; import { StoreType } from "../data/data"; import { FormFieldState } from "../store/formState"; diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index eb6cc91b3f..9001bcfcd0 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -5,10 +5,14 @@ import { useStore } from "react-redux"; import { EditorPanel } from "../component/reusable/panel"; import "./panel.scss"; import React from "react"; -import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { AppWrapper, CAppWrapper, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; import { useShown } from "../hook/shown"; +import { StoreType } from "../data/data"; +import { CHandleFactory } from "../data/handle"; +import { FormStateHandleFactory } from "../data/form"; +import { modelsSlice } from "../store/models"; export type PanelConfig = { basic: SchemaLayout[], @@ -34,12 +38,14 @@ export class PanelLayout extends Layout { component = (props: LayoutProps<{}>) => { let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + let appWrapper = useContext(CAppWrapper); - let shown = useShown(this.config.shown, true, modelsWrapper, ValueSelectors.Models); + let shown = useShown(this.config.shown, true, StoreType.Models); let store = useStore(); - let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); + let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreType.Models).raw(); let mapLayoutsToComponents = (views: Layout[]) => views.map((child, idx) => { let LayoutComponent = child.component; @@ -50,9 +56,8 @@ export class PanelLayout extends Layout { let modalChildren = (!!this.advanced) ? mapLayoutsToComponents(this.advanced) : undefined; let submit = () => { - //formController.saveToModels(store.getState()); simulationInfoPromise.then(simulationInfo => { - (modelsWrapper as ModelsWrapper).saveToServer(simulationInfo, Object.keys(schema.models), store.getState()); + appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); }) } From e61db8cb600dfc4eb8fdad86d6f3831412d6187f Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 5 Apr 2023 21:34:04 +0000 Subject: [PATCH 22/68] wip continue data refactor --- react/src/component/simulation.tsx | 4 +- react/src/data/data.ts | 31 +++++---- react/src/data/form.ts | 103 ++++++++++++++++++++--------- react/src/data/handle.ts | 45 ++++++++++--- react/src/hook/shown.ts | 4 +- react/src/layout/form.tsx | 23 +++---- react/src/layout/input/enum.tsx | 10 +-- react/src/layout/panel.tsx | 19 +++--- react/src/layout/report.tsx | 38 ++++------- react/src/store/formState.ts | 11 ++- react/src/utility/string.ts | 4 +- 11 files changed, 179 insertions(+), 113 deletions(-) diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 03c5fbca97..5a6e41d80a 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -33,7 +33,7 @@ import { StoreState } from "../store/common"; import { configureStore } from "@reduxjs/toolkit"; import { formStatesSlice } from "../store/formState"; import { BaseHandleFactory, CHandleFactory } from "../data/handle"; -import { StoreType } from "../data/data"; +import { StoreTypes } from "../data/data"; export type SimulationInfoRaw = { models: StoreState, @@ -255,7 +255,7 @@ export function SimulationOuter(props) { let currentRelativeRouter = new RelativeRouteHelper(pathPrefix); let handleFactory = useContext(CHandleFactory); - let simNameHandle = handleFactory.createHandle(new Dependency("simulation.name"), StoreType.Models).hook(); + let simNameHandle = handleFactory.createHandle(new Dependency("simulation.name"), StoreTypes.Models).hook(); useEffect(() => { document.title = simNameHandle.value as string; diff --git a/react/src/data/data.ts b/react/src/data/data.ts index bd2dab90f6..265157f6f0 100644 --- a/react/src/data/data.ts +++ b/react/src/data/data.ts @@ -1,21 +1,26 @@ import { ModelSelector, ModelWriteActionCreator } from "../store/common"; -import { formActions, FormFieldState, formSelectors } from "../store/formState"; -import { modelActions, modelSelectors } from "../store/models"; +import { formActions, FormFieldState, FormModelState, formSelectors } from "../store/formState"; +import { modelActions, modelSelectors, ModelState } from "../store/models"; -export enum StoreType { - Models, - FormState +export type StoreType = "Models" | "FormState" + +export const StoreTypes:{ + Models: StoreType, + FormState: StoreType> +} = { + Models: "Models", + FormState: "FormState" } -export const getModelReadSelector = (type: StoreType) => { - return (type === StoreType.Models ? modelSelectors.selectModel : formSelectors.selectModel) as ModelSelector; +export const getModelReadSelector = (type: StoreType) => { + return (type === StoreTypes.Models ? modelSelectors.selectModel : formSelectors.selectModel) as ModelSelector; } -export const getModelWriteActionCreator = (type: StoreType) => { - let mac = (type === StoreType.Models ? modelActions.updateModel : formActions.updateModel) as ModelWriteActionCreator; +export const getModelWriteActionCreator = (type: StoreType) => { + let mac = (type === StoreTypes.Models ? modelActions.updateModel : formActions.updateModel) as ModelWriteActionCreator; return (name: string, value: V) => mac({ name, value }); } -export const getModelNamesSelector = (type: StoreType) => { - return (type === StoreType.Models ? modelSelectors.selectModelNames : formSelectors.selectModelNames); +export const getModelNamesSelector = (type: StoreType) => { + return (type === StoreTypes.Models ? modelSelectors.selectModelNames : formSelectors.selectModelNames); } export type ValueSelector = (v: T) => any; @@ -25,6 +30,6 @@ export const ValueSelectors = { Form: (v: FormFieldState) => v.value } -export const getValueSelector = (storeType: StoreType): ((v: any) => any) | ((v: FormFieldState) => unknown) => { - return storeType === StoreType.Models ? ValueSelectors.Models : ValueSelectors.Form; +export const getValueSelector = (storeType: StoreType): ((v: F) => any) | ((v: F) => any) => { + return storeType === StoreTypes.Models ? ValueSelectors.Models : ValueSelectors.Form; } diff --git a/react/src/data/form.ts b/react/src/data/form.ts index b0fd1fad17..265d082e24 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -1,18 +1,24 @@ +import { useState } from "react"; import { Dispatch, AnyAction } from "redux"; import { ArrayFieldElement, ArrayFieldState } from "../store/common"; +import { initialFormStateFromValue } from "../store/formState"; import { Schema } from "../utility/schema"; -import { StoreType } from "./data"; +import { StoreType, StoreTypes } from "./data"; import { ArrayDataHandle, BaseHandleFactory, DataHandle, EmptyDataHandle } from "./handle"; -type SaveFunc = (state: any, dispatch: Dispatch) => void +type FormActionFunc = (state: any, dispatch: Dispatch) => void +type FormSelectorFunc = (state: any) => V -type SaveFuncKeyPair = { +type FormActionsKeyPair = { key: any, - saveFn: SaveFunc + save: FormActionFunc, + cancel: FormActionFunc, + valid: FormSelectorFunc } export class FormStateHandleFactory extends BaseHandleFactory { - private updated: SaveFuncKeyPair[] = [] + private updated: FormActionsKeyPair[] = [] + private listeners: (() => void)[] = []; constructor(private schema: Schema) { super(); @@ -52,53 +58,86 @@ export class FormStateHandleFactory extends BaseHandleFactory { })(); } - private addToUpdated = (key: any, saveFn: SaveFunc) => { - let idx = this.updated.findIndex(u => u.key === key); + private addToUpdated = (kp: FormActionsKeyPair) => { + let idx = this.updated.findIndex(u => u.key === kp.key); if(idx >= 0) { this.updated.splice(idx, 1); } - this.updated.push({ - key, - saveFn - }) + this.updated.push(kp) + } + + private notifyListeners() { + this.listeners.forEach(l => l()); } save(state: any, dispatch: Dispatch) { - this.updated.forEach(u => u.saveFn(state, dispatch)); + this.updated.forEach(u => u.save(state, dispatch)); + this.updated = []; + this.notifyListeners(); + } + + cancel(state: any, dispatch: Dispatch) { + this.updated.forEach(u => u.cancel(state, dispatch)); this.updated = []; + this.notifyListeners(); + } + + isDirty(): boolean { + return this.updated.length > 0; + } + + isValid(state: any): boolean { + return !this.updated.map(u => !!u.valid(state)).includes(false); + } + + useUpdates() { + let [v, u] = useState({}); + this.listeners.push(() => u({})); } - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { let edh = super.createHandle(dependency, type); - if(type === StoreType.FormState) { + if(type === StoreTypes.FormState) { return this.emptyDataHandleFor>(edh, (dh: DataHandle) => { - this.addToUpdated( - dh, - (state: any, dispatch: Dispatch) => { - let f = super.createHandle(dependency, StoreType.FormState).initialize(state); - let m = super.createHandle(dependency, StoreType.Models).initialize(state); - let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f.value); - m.write(v, dispatch); + let f = (state: any) => super.createHandle(dependency, StoreTypes.FormState).initialize(state); + let m = (state: any) => super.createHandle(dependency, StoreTypes.Models).initialize(state); + this.addToUpdated({ + key: dh, + save: (state: any, dispatch: Dispatch) => { + let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f(state).value); + m(state).write(v, dispatch); + }, + cancel: (state: any, dispatch: Dispatch) => { + f(state).write(initialFormStateFromValue(m(state).value), dispatch); + }, + valid: (state: any): boolean => { + return f(state).value.valid; } - ); + }); }) } return edh; } - createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { + createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { let edh = super.createArrayHandle(dependency, type); - if(type === StoreType.FormState) { + if(type === StoreTypes.FormState) { return this.emptyDataHandleFor>(edh, (dh: ArrayDataHandle) => { - this.addToUpdated( - dh, - (state: any, dispatch: Dispatch) => { - let f = super.createArrayHandle(dependency, StoreType.FormState).initialize(state); - let m = super.createArrayHandle(dependency, StoreType.Models).initialize(state); - let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f.value); - m.write(v, dispatch); + let f = (state) => super.createArrayHandle(dependency, StoreTypes.FormState).initialize(state); + let m = (state) => super.createArrayHandle(dependency, StoreTypes.Models).initialize(state); + this.addToUpdated({ + key: dh, + save: (state: any, dispatch: Dispatch) => { + let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f(state).value); + m(state).write(v, dispatch); + }, + cancel: (state: any, dispatch: Dispatch) => { + f(state).write(initialFormStateFromValue(m(state).value), dispatch); + }, + valid: (state: any): boolean => { + return f(state).value.valid; } - ); + }); }) } return edh; diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 3b617ea06d..17c589131a 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -2,7 +2,7 @@ import React from "react"; import { useSelector } from "react-redux"; import { AnyAction, Dispatch } from "redux"; import { ArrayFieldElement, ArrayFieldState } from "../store/common"; -import { getModelReadSelector, getModelWriteActionCreator, StoreType } from "./data"; +import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, StoreType, StoreTypes } from "./data"; export const CHandleFactory = React.createContext(undefined); @@ -34,14 +34,15 @@ export interface EmptyDataHandle = DataHandle> { } export abstract class HandleFactory { - abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; - abstract createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle; + abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; + abstract createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle; } export class BaseHandleFactory extends HandleFactory { - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { let ms = getModelReadSelector(type)(dependency.modelName); let mac = getModelWriteActionCreator(type); + let vs = getValueSelector(type); let cdh = (value: V): DataHandle => { return new (class extends DataHandle { write = (value: V, dispatch: Dispatch) => { @@ -51,17 +52,18 @@ export class BaseHandleFactory extends HandleFactory { } return { initialize: (state: any) => { - return cdh(ms(state)); + return cdh(vs(ms(state))); }, hook: () => { - return cdh(useSelector(ms)); + return cdh(vs(useSelector(ms))); } } } - createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { + createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { let ms = getModelReadSelector(type)(dependency.modelName); let mac = getModelWriteActionCreator(type); + let vs = getValueSelector(type); let cdh = (value: V): ArrayDataHandle => { return new (class extends ArrayDataHandle { write = (value: V, dispatch: Dispatch) => { @@ -83,11 +85,36 @@ export class BaseHandleFactory extends HandleFactory { } return { initialize: (state: any) => { - return cdh(ms(state)); + return cdh(vs(ms(state))); }, hook: () => { - return cdh(useSelector(ms)); + return cdh(vs(useSelector(ms))); } } } } + +export type DependencyValues = { + getValues: () => F[] +} + +/** + * Read-only alternative to handles that supports wildcards + */ +export class DependencyReader { + constructor(private dependencies: Dependency[], private type: StoreType) { + + } + + hook = (): DependencyValues => { + let vs = getModelReadSelector(this.type) + + + let ms = getModelReadSelector(this.type)(dependency.modelName); + + } + + initialize = (state: any): DependencyValues => { + + } +} diff --git a/react/src/hook/shown.ts b/react/src/hook/shown.ts index f2e9fa51a7..49d63bff8b 100644 --- a/react/src/hook/shown.ts +++ b/react/src/hook/shown.ts @@ -1,9 +1,9 @@ import { useContext } from "react"; -import { StoreType } from "../data/data"; +import { StoreTypes } from "../data/data"; import { CHandleFactory } from "../data/handle"; import { interpolate } from "../utility/string" -export function useShown(shownStr: string, defaultValue: boolean, type: StoreType) { +export function useShown(shownStr: string, defaultValue: boolean, type: StoreTypes) { let dhf = useContext(CHandleFactory); if(shownStr) { let shown = interpolate(shownStr).withDependencies(dhf, type).evaluated(); diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index b1ebb3ff5e..b4db583511 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -12,12 +12,13 @@ import { useDispatch } from "react-redux"; import { CSchema } from "../data/appwrapper"; import { FormStateHandleFactory } from "../data/form"; import { CHandleFactory } from "../data/handle"; -import { StoreType } from "../data/data"; +import { StoreTypes } from "../data/data"; import { FormFieldState } from "../store/formState"; export function FormControllerElement(props: {children?: React.ReactNode}) { let schema = useContext(CSchema); let formHandleFactory = new FormStateHandleFactory(schema); + formHandleFactory.useUpdates(); // TODO: form controller might need to "subscribe to updates" during save return ( @@ -72,7 +73,7 @@ export class FieldGridLayout extends Layout { let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let schema = useContext(CSchema); let dispatch = useDispatch(); - let gridShown = useShown(this.config.shown, true, StoreType.FormState); + let gridShown = useShown(this.config.shown, true, StoreTypes.FormState); if (! gridShown) { return <> @@ -93,7 +94,7 @@ export class FieldGridLayout extends Layout { for(let idx = 0; idx < rows.length; idx++) { let row = rows[idx]; - let shown = useShown(row.shown, true, StoreType.FormState); + let shown = useShown(row.shown, true, StoreTypes.FormState); let fields = row.fields; let labelElement = someRowHasLabel ? ({row.label || ""}) : undefined; let rowElement = shown ? ( @@ -101,9 +102,8 @@ export class FieldGridLayout extends Layout { {labelElement ? {labelElement} : undefined} {columns.map((_, index) => { let fieldDependency = new Dependency(fields[index]); - let fieldHandle = formHandleFactory.createHandle>(fieldDependency, StoreType.FormState).hook(); + let fieldHandle = formHandleFactory.createHandle>(fieldDependency, StoreTypes.FormState).hook(); let fieldType = schema.models[fieldDependency.modelName][fieldDependency.fieldName].type; - let active = fieldHandle.value?.active !== undefined ? fieldHandle.value.active : true; return ( { fieldHandle.write({ valid: fieldType.validate(value), touched: true, - value, - active + value }, dispatch) }} dependency={fieldDependency} @@ -152,13 +151,12 @@ export class FieldListLayout extends Layout { return <> {fields.map((fieldDepString, idx) => { let fieldDep = new Dependency(fieldDepString); - let fieldHandle = formHandleFactory.createHandle>(fieldDep, StoreType.FormState).hook(); + let fieldHandle = formHandleFactory.createHandle>(fieldDep, StoreTypes.FormState).hook(); let fieldType = schema.models[fieldDep.modelName][fieldDep.fieldName].type; - let active = fieldHandle.value?.active !== undefined ? fieldHandle.value.active : true; let fieldSchema = schema.models[fieldDep.modelName][fieldDep.fieldName]; - let shown = useShown(fieldSchema.shown, true, StoreType.FormState); + let shown = useShown(fieldSchema.shown, true, StoreTypes.FormState); - if(shown && active) { + if(shown) { return { fieldHandle.write({ valid: fieldType.validate(value), touched: true, - value, - active + value }, dispatch) }} inputComponent={fieldSchema.type.component}/> diff --git a/react/src/layout/input/enum.tsx b/react/src/layout/input/enum.tsx index 082950b6c4..4b54008a36 100644 --- a/react/src/layout/input/enum.tsx +++ b/react/src/layout/input/enum.tsx @@ -1,6 +1,5 @@ import React, { ChangeEventHandler, useContext, useEffect, useState } from "react"; import { AppWrapper, CAppName, CSimulationInfoPromise } from "../../data/appwrapper"; -import { CFormController } from "../../data/formController"; import { CRouteHelper } from "../../utility/route"; import { Dependency } from "../../data/dependency"; import { Form } from "react-bootstrap"; @@ -8,6 +7,8 @@ import { FunctionComponent } from "react"; import { InputComponentProps, InputConfigBase, InputLayout } from "./input"; import { LayoutProps } from "../layout"; import { pollStatefulCompute } from "../../utility/compute"; +import { CHandleFactory } from "../../data/handle"; +import { StoreTypes } from "../../data/data"; export type EnumAllowedValues = { value: string, displayName: string }[] @@ -116,11 +117,12 @@ export class SimulationListEnumInputLayout extends EnumInputBaseLayout>> = (props) => { const routeHelper = useContext(CRouteHelper); const [optionList, updateOptionList] = useState(undefined); - const formController = useContext(CFormController); + const handleFactory = useContext(CHandleFactory); //TODO(pjm): these 2 lines are specific to the omega app but could be generalized const suffix = props.dependency.fieldName.match(/_\d+/); - const simType = formController.getFormStateAccessor().getFieldValue(new Dependency( - `simWorkflow.simType${suffix}`)).value as string; + const simType = handleFactory.createHandle(new Dependency( + `simWorkflow.simType${suffix}`), StoreTypes.FormState).hook().value as string; + useEffect(() => { if (! simType) { return; diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 9001bcfcd0..07751a7325 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -1,15 +1,15 @@ import { useContext } from "react"; import { interpolate } from "../utility/string"; import { LayoutProps, Layout } from "./layout"; -import { useStore } from "react-redux"; +import { useDispatch, useStore } from "react-redux"; import { EditorPanel } from "../component/reusable/panel"; import "./panel.scss"; import React from "react"; -import { AppWrapper, CAppWrapper, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { CAppWrapper, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; import { useShown } from "../hook/shown"; -import { StoreType } from "../data/data"; +import { StoreTypes } from "../data/data"; import { CHandleFactory } from "../data/handle"; import { FormStateHandleFactory } from "../data/form"; import { modelsSlice } from "../store/models"; @@ -37,15 +37,15 @@ export class PanelLayout extends Layout { component = (props: LayoutProps<{}>) => { let simulationInfoPromise = useContext(CSimulationInfoPromise); - let schema = useContext(CSchema); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let appWrapper = useContext(CAppWrapper); - let shown = useShown(this.config.shown, true, StoreType.Models); + let shown = useShown(this.config.shown, true, StoreTypes.Models); let store = useStore(); + let dispatch = useDispatch(); - let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreType.Models).raw(); + let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); let mapLayoutsToComponents = (views: Layout[]) => views.map((child, idx) => { let LayoutComponent = child.component; @@ -56,6 +56,7 @@ export class PanelLayout extends Layout { let modalChildren = (!!this.advanced) ? mapLayoutsToComponents(this.advanced) : undefined; let submit = () => { + formHandleFactory.save(store.getState(), dispatch); simulationInfoPromise.then(simulationInfo => { appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); }) @@ -64,9 +65,9 @@ export class PanelLayout extends Layout { let formProps = { submit: submit, - cancel: formController.cancelChanges, - showButtons: formController.isFormStateDirty(), - formValid: formController.isFormStateValid(), + cancel: formHandleFactory.cancel(store.getState(), dispatch), + showButtons: formHandleFactory.isDirty(), + formValid: formHandleFactory.isValid(store.getState()), mainChildren, modalChildren, title: title || this.name, diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index 11bc1b7e16..f8f71e4cc0 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -12,15 +12,14 @@ import { AnimationReader, CReportEventManager, SimulationFrame } from "../data/r import React from "react"; import { CPanelController } from "../data/panel"; import { LAYOUTS } from "./layouts"; -import { CModelsWrapper, getModelValues } from "../data/wrapper"; -import { ModelsAccessor } from "../data/accessor"; -import { CFormController } from "../data/formController"; import { CAppName, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { CRouteHelper } from "../utility/route"; import { ModelState } from "../store/models"; import { useShown } from "../hook/shown"; -import { ValueSelectors } from "../utility/string"; +import { CHandleFactory } from "../data/handle"; +import { StoreTypes, ValueSelectors } from "../data/data"; +import { FormFieldState } from "../store/formState"; export type ReportVisualProps = { data: L, model: ModelState }; @@ -54,14 +53,10 @@ export class AutoRunReportLayout extends Layout { let simulationInfoPromise = useContext(CSimulationInfoPromise); let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); - let modelsWrapper = useContext(CModelsWrapper); - let formController = useContext(CFormController); + let handleFactory = useContext(CHandleFactory); let reportDependencies = dependencies.map(dependencyString => new Dependency(dependencyString)); - - let dependentValuesAccessor = new ModelsAccessor(modelsWrapper, [...formController.getDependencies(), ...reportDependencies]); - let dependentValues = dependentValuesAccessor.getValues().map(dv => dv.value); - + let dependentValues = reportDependencies.map(d => ValueSelectors.Form(handleFactory.createHandle(d, StoreTypes.FormState).hook().value as FormFieldState)); let [simulationData, updateSimulationData] = useState(undefined); let simulationPollingVersionRef = useRef(uuidv4()) @@ -69,9 +64,7 @@ export class AutoRunReportLayout extends Layout { useEffect(() => { updateSimulationData(undefined); - let pollingVersion = uuidv4(); - //simulationPollingVersionRef.current = pollingVersion; - simulationInfoPromise.then(({ models, simulationId, simulationType, version }) => { + simulationInfoPromise.then(({ models, simulationId }) => { updateModel(models[report]); pollRunReport(routeHelper, { appName, @@ -80,12 +73,7 @@ export class AutoRunReportLayout extends Layout { report: report, forceRun: false, callback: (simulationData) => { - // guard concurrency - //if(simulationPollingVersionRef.current === pollingVersion) { updateSimulationData(simulationData); - //} else { - // console.log("polling data was not from newest request"); - //} } }) }) @@ -114,14 +102,13 @@ export function useAnimationReader(reportName: string, reportGroupName: string, panelController.setShown(s); } }, [animationReader?.frameCount]) + let handleFactory = useContext(CHandleFactory); let reportEventManager = useContext(CReportEventManager); - let modelsWrapper = useContext(CModelsWrapper); let simulationInfoPromise = useContext(CSimulationInfoPromise); let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); let reportEventsVersionRef = useRef(uuidv4()) - let frameIdDependencies = frameIdFields.map(f => new Dependency(f)); - let frameIdAccessor = new ModelsAccessor(modelsWrapper, frameIdDependencies); + let frameIdHandles = frameIdFields.map(f => new Dependency(f)).map(d => handleFactory.createHandle(d, StoreTypes.Models).hook()); function reportStatus(reportName, simulationData) { if (simulationData.reports) { @@ -157,7 +144,7 @@ export function useAnimationReader(reportName: string, reportGroupName: string, appName, computeJobSerial, computeJobHash, - frameIdValues: frameIdAccessor.getValues().map(fv => fv.value), + frameIdValues: frameIdHandles.map(h => ValueSelectors.Models(h.value)), frameCount: s.frameCount, hasAnimationControls: s.hasAnimationControls, }); @@ -202,10 +189,11 @@ export class ManualRunReportLayout extends Layout { let showAnimationController = 'showAnimationController' in this.config ? !!this.config.showAnimationController : true; - let modelsWrapper = useContext(CModelsWrapper); + let handleFactory = useContext(CHandleFactory); let store = useStore(); - let shown = useShown(this.config.shown, true, modelsWrapper, ValueSelectors.Models); - let model = getModelValues([reportName], modelsWrapper, store.getState())[reportName]; + let shown = useShown(this.config.shown, true, StoreTypes.Models); + //let model = getModelValues([reportName], modelsWrapper, store.getState())[reportName]; + let reportModel = // need to deal with * let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); return ( <> diff --git a/react/src/store/formState.ts b/react/src/store/formState.ts index b4d001c0f1..e677e79a32 100644 --- a/react/src/store/formState.ts +++ b/react/src/store/formState.ts @@ -3,8 +3,15 @@ import { ArrayFieldState, makeSlice } from "./common" export type FormFieldState = { valid: boolean, value: T | ArrayFieldState, - touched: boolean, - active: boolean + touched: boolean +} + +export function initialFormStateFromValue(value: T): FormFieldState { + return { + valid: true, + value, + touched: false + } } export type FormModelState = { diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 60dddeda29..9a03417238 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -1,4 +1,4 @@ -import { getValueSelector, StoreType } from "../data/data"; +import { getValueSelector, StoreTypes } from "../data/data"; import { Dependency } from "../data/dependency"; import { HandleFactory } from "../data/handle"; @@ -36,7 +36,7 @@ export class InterpolationBase { ) } - withDependencies(handleFactory: HandleFactory, type: StoreType): InterpolationResult { + withDependencies(handleFactory: HandleFactory, type: StoreTypes): InterpolationResult { let valueSelector = getValueSelector(type) as (v: F) => any; let mappingsArr = this.matches.map(([originalString, mappedGroup]) => { From 374d6ed0e53590761ea746edc0c55e38b9d05842 Mon Sep 17 00:00:00 2001 From: garsuga Date: Mon, 10 Apr 2023 21:27:15 +0000 Subject: [PATCH 23/68] wip update react data management --- react/src/component/reusable/form.tsx | 52 ++++---- react/src/component/simulation.tsx | 3 +- react/src/data/alias.ts | 50 ++++++++ react/src/data/data.ts | 24 ++-- react/src/data/form.ts | 91 +++++--------- react/src/data/handle.ts | 118 ++++++++---------- react/src/hook/shown.ts | 4 +- react/src/layout/arrange/stack.tsx | 4 - react/src/layout/arrange/waterfall.tsx | 5 - react/src/layout/beamline.tsx | 103 ++++++++------- react/src/layout/form.tsx | 29 ++--- react/src/layout/input/enum.tsx | 6 +- react/src/layout/input/file.tsx | 9 +- react/src/layout/input/input.tsx | 5 - react/src/layout/layout.ts | 4 +- react/src/layout/missing.tsx | 4 - react/src/layout/multipanel.tsx | 4 - react/src/layout/navbar.tsx | 54 ++++---- react/src/layout/panel.tsx | 4 - react/src/layout/report.tsx | 19 +-- react/src/layout/report/graph2d.tsx | 4 - react/src/layout/report/heatplot.tsx | 4 - react/src/layout/report/histogram2d.tsx | 4 - react/src/layout/report/table.tsx | 4 - .../shadow/beamlineWatchpointReports.tsx | 4 - react/src/layout/tabs.tsx | 12 -- react/src/layout/text.tsx | 4 - react/src/utility/compute.ts | 9 +- react/src/utility/string.ts | 4 +- 29 files changed, 288 insertions(+), 353 deletions(-) create mode 100644 react/src/data/alias.ts diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 16ba2edf89..43b5efbc8a 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -10,16 +10,15 @@ import React, { useEffect } from "react"; import { - formActions, - formSelectors + formStatesSlice, + initialFormStateFromValue } from "../../store/formState"; -import { FormController, formStateFromModel } from "../../data/formController"; import { useStore } from "react-redux"; -import { CModelsWrapper, CFormStateWrapper, FormStateWrapper, ModelsWrapper, AbstractModelsWrapper } from "../../data/wrapper"; -import { CSchema, CSimulationInfoPromise } from "../../data/appwrapper"; +import { AppWrapper, CSchema } from "../../data/appwrapper"; import { SimulationInfo } from "../simulation"; -import { Schema } from "../../utility/schema"; -import { AnyAction, Store } from "redux"; +import { AnyAction, Dispatch, Store } from "redux"; +import { FormStateHandleFactory } from "../../data/form"; +import { modelsSlice } from "../../store/models"; export function FormField(props) { let { label, tooltip, ...passedProps } = props; @@ -46,13 +45,26 @@ export function EditorForm(props) { ); } -export function formActionFunctions(formController: FormController, store: Store, simulationInfoPromise: Promise, schema: Schema, modelsWrapper: ModelsWrapper): { cancel: () => void, submit: () => void } { +export function formActionFunctions(config: { + formHandleFactory: FormStateHandleFactory, + store: Store, + simulationInfoPromise: Promise, + appWrapper: AppWrapper, + dispatch: Dispatch +}): { cancel: () => void, submit: () => void } { + let { + formHandleFactory, + store, + simulationInfoPromise, + appWrapper, + dispatch + } = config; return { - cancel: () => formController.cancelChanges(store.getState()), + cancel: () => formHandleFactory.cancel(store.getState(), dispatch), submit: () => { - formController.saveToModels(store.getState()); + formHandleFactory.save(store.getState(), dispatch); simulationInfoPromise.then(simulationInfo => { - modelsWrapper.saveToServer(simulationInfo, Object.keys(schema.models), store.getState()) + appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); }) } } @@ -65,20 +77,16 @@ export function FormStateInitializer(props) { let store = useStore(); - let models = useContext(CModelsWrapper); - let formState = new FormStateWrapper({ - formActions, - formSelectors - }) - - let modelNames = (models as ModelsWrapper).getModelNames(store.getState()); + let ms = store.getState()[modelsSlice.name] + let fs = store.getState()[formStatesSlice.name]; + let modelNames = Object.keys(ms); useEffect(() => { let state = store.getState(); modelNames.map(mn => { return { modelName: mn, - value: models.getModel(mn, state) + value: ms[mn] } }).forEach(({ modelName, value }) => { if(!value) { @@ -88,15 +96,13 @@ export function FormStateInitializer(props) { if(!modelSchema) { throw new Error(`could not get schema for model=${modelName}`); } - formState.updateModel(modelName, formStateFromModel(value, modelSchema, schema), store.getState()); + fs[modelName] = mapProperties(ms, ([_, fv]) => initialFormStateFromValue(fv)); }); updateHasInit(true); }, []) return hasInit && ( - - {props.children} - + <>{props.children} ); } diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 5a6e41d80a..cee71bec14 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -58,6 +58,7 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let [simulationInfoPromise, updateSimulationInfoPromise] = useState(undefined); let [hasInit, updateHasInit] = useState(false); let appName = useContext(CAppName); + let schema = useContext(CSchema); let routeHelper = useContext(CRouteHelper); let dispatch = useDispatch(); @@ -86,7 +87,7 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri return hasInit && simulationInfoPromise && ( - + {props.children} diff --git a/react/src/data/alias.ts b/react/src/data/alias.ts new file mode 100644 index 0000000000..8326f25b55 --- /dev/null +++ b/react/src/data/alias.ts @@ -0,0 +1,50 @@ +import { Dispatch, AnyAction } from "redux"; +import { ArrayFieldState, StoreState } from "../store/common"; +import { Schema } from "../utility/schema"; +import { getValueSelector, StoreType } from "./data"; +import { Dependency } from "./dependency"; +import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; + +export type ArrayAliases = { + realDataLocation: { + modelName: string, + fieldName: string, + index: number + }, + realSchemaName: string, + fake: string +}[] + +export class HandleFactoryWithArrayAliases extends HandleFactory { + constructor(schema: Schema, private aliases: ArrayAliases, private parent: HandleFactory) { + super(schema); + } + + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle> { + let alias = this.aliases.find(a => a.fake === dependency.modelName); + if(alias !== undefined) { + let edh = this.parent.createHandle(new Dependency(`${alias.realDataLocation.modelName}.${alias.realDataLocation.fieldName}`), type); + return new (class implements EmptyDataHandle { + private createDummyHandle(dh: DataHandle): DataHandle { + let mv = getValueSelector(type)(dh.value)[alias.realDataLocation.index]; + let fv = mv[dependency.fieldName]; + return new (class extends DataHandle { + write(value: F, state: StoreState, dispatch: Dispatch) { + let av = getValueSelector(type)(dh.value) as ArrayFieldState; + av[alias.realDataLocation.index][dependency.fieldName] = value; + dh.write(dh.value, state, dispatch); + } + })(fv); + } + + initialize(state: any): DataHandle { + return this.createDummyHandle(edh.initialize(state)); + } + hook(): DataHandle { + return this.createDummyHandle(edh.hook()); + } + })(); + } + return this.parent.createHandle(dependency, type); + } +} diff --git a/react/src/data/data.ts b/react/src/data/data.ts index 265157f6f0..69391f3d88 100644 --- a/react/src/data/data.ts +++ b/react/src/data/data.ts @@ -1,19 +1,22 @@ import { ModelSelector, ModelWriteActionCreator } from "../store/common"; -import { formActions, FormFieldState, FormModelState, formSelectors } from "../store/formState"; -import { modelActions, modelSelectors, ModelState } from "../store/models"; +import { formActions, FormFieldState, FormModelState, formSelectors, formStatesSlice } from "../store/formState"; +import { modelActions, modelSelectors, modelsSlice, ModelState } from "../store/models"; +import { SchemaModel } from "../utility/schema"; -export type StoreType = "Models" | "FormState" +export class StoreType { + constructor(public name: string) {} +} export const StoreTypes:{ Models: StoreType, FormState: StoreType> } = { - Models: "Models", - FormState: "FormState" + Models: new StoreType(modelsSlice.name), + FormState: new StoreType(formStatesSlice.name) } -export const getModelReadSelector = (type: StoreType) => { - return (type === StoreTypes.Models ? modelSelectors.selectModel : formSelectors.selectModel) as ModelSelector; +export const getModelReadSelector = (type: StoreType) => { + return (type === StoreTypes.Models ? modelSelectors.selectModel : formSelectors.selectModel) as ModelSelector; } export const getModelWriteActionCreator = (type: StoreType) => { let mac = (type === StoreTypes.Models ? modelActions.updateModel : formActions.updateModel) as ModelWriteActionCreator; @@ -30,6 +33,11 @@ export const ValueSelectors = { Form: (v: FormFieldState) => v.value } -export const getValueSelector = (storeType: StoreType): ((v: F) => any) | ((v: F) => any) => { +export const getValueSelector = (storeType: StoreType): ((v: F) => any) => { return storeType === StoreTypes.Models ? ValueSelectors.Models : ValueSelectors.Form; } + +export function newModelFromSchema(modelSchema: SchemaModel, overrides: {[key: string]: any}): ModelState { + let defaults = Object.fromEntries(Object.entries(modelSchema).filter(([name, value]) => value.defaultValue !== undefined).map(([name, value]) => [name, value.defaultValue])) + return Object.assign(defaults, overrides); +} diff --git a/react/src/data/form.ts b/react/src/data/form.ts index 265d082e24..d19d3e89f8 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -1,10 +1,11 @@ import { useState } from "react"; -import { Dispatch, AnyAction } from "redux"; -import { ArrayFieldElement, ArrayFieldState } from "../store/common"; -import { initialFormStateFromValue } from "../store/formState"; +import { Dispatch, AnyAction, Store } from "redux"; +import { StoreState } from "../store/common"; +import { FormModelState, initialFormStateFromValue } from "../store/formState"; +import { ModelState } from "../store/models"; import { Schema } from "../utility/schema"; import { StoreType, StoreTypes } from "./data"; -import { ArrayDataHandle, BaseHandleFactory, DataHandle, EmptyDataHandle } from "./handle"; +import { BaseHandleFactory, DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; type FormActionFunc = (state: any, dispatch: Dispatch) => void type FormSelectorFunc = (state: any) => V @@ -16,42 +17,34 @@ type FormActionsKeyPair = { valid: FormSelectorFunc } -export class FormStateHandleFactory extends BaseHandleFactory { +export function formStateFromModelState(modelState: ModelState): FormModelState { + return mapProperties(modelState, (name, value) => initialFormStateFromValue(value)); +} + +export class FormStateHandleFactory extends HandleFactory { private updated: FormActionsKeyPair[] = [] private listeners: (() => void)[] = []; - constructor(private schema: Schema) { - super(); + constructor(schema: Schema, private parent: HandleFactory) { + super(schema); } - private emptyDataHandleFor>(parent: EmptyDataHandle, updateCallback: (dh: D) => void): EmptyDataHandle { - return new (class implements EmptyDataHandle { - private dataHandleFor(parent: DataHandle): D { - let dh = new (class extends ArrayDataHandle { - append(element: ArrayFieldElement, dispatch: Dispatch) { - (parent as ArrayDataHandle).append(element, dispatch); - updateCallback(dh); - } - appendAt(index: number, element: ArrayFieldElement, dispatch: Dispatch) { - (parent as ArrayDataHandle).appendAt(index, element, dispatch); - updateCallback(dh); - } - removeAt(index: number, dispatch: Dispatch) { - (parent as ArrayDataHandle).removeAt(index, dispatch); + private emptyDataHandleFor(parent: EmptyDataHandle, updateCallback: (dh: DataHandle) => void): EmptyDataHandle { + return new (class implements EmptyDataHandle { + private dataHandleFor(parent: DataHandle): DataHandle { + let dh: DataHandle = new (class extends DataHandle { + write = (value: F, state: StoreState, dispatch: Dispatch) => { + parent.write(value, state, dispatch); updateCallback(dh); } - write = (value: V, dispatch: Dispatch) => { - parent.write(value, dispatch); - updateCallback(dh); - } - })(parent.value) as any as D; + })(parent.value); return dh; } - initialize(state: any): D { + initialize(state: any): DataHandle { return this.dataHandleFor(parent.initialize(state)); } - hook(): D { + hook(): DataHandle { return this.dataHandleFor(parent.hook()); } @@ -95,44 +88,20 @@ export class FormStateHandleFactory extends BaseHandleFactory { this.listeners.push(() => u({})); } - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { - let edh = super.createHandle(dependency, type); - if(type === StoreTypes.FormState) { - return this.emptyDataHandleFor>(edh, (dh: DataHandle) => { - let f = (state: any) => super.createHandle(dependency, StoreTypes.FormState).initialize(state); - let m = (state: any) => super.createHandle(dependency, StoreTypes.Models).initialize(state); - this.addToUpdated({ - key: dh, - save: (state: any, dispatch: Dispatch) => { - let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f(state).value); - m(state).write(v, dispatch); - }, - cancel: (state: any, dispatch: Dispatch) => { - f(state).write(initialFormStateFromValue(m(state).value), dispatch); - }, - valid: (state: any): boolean => { - return f(state).value.valid; - } - }); - }) - } - return edh; - } - - createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { - let edh = super.createArrayHandle(dependency, type); + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + let edh = this.parent.createHandle(dependency, type); if(type === StoreTypes.FormState) { - return this.emptyDataHandleFor>(edh, (dh: ArrayDataHandle) => { - let f = (state) => super.createArrayHandle(dependency, StoreTypes.FormState).initialize(state); - let m = (state) => super.createArrayHandle(dependency, StoreTypes.Models).initialize(state); + return this.emptyDataHandleFor(edh, (dh: DataHandle) => { + let f = (state: any) => this.parent.createHandle(dependency, StoreTypes.FormState).initialize(state); + let m = (state: any) => this.parent.createHandle(dependency, StoreTypes.Models).initialize(state); this.addToUpdated({ key: dh, - save: (state: any, dispatch: Dispatch) => { + save: (state: StoreState, dispatch: Dispatch) => { let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f(state).value); - m(state).write(v, dispatch); + m(state).write(v, state, dispatch); }, - cancel: (state: any, dispatch: Dispatch) => { - f(state).write(initialFormStateFromValue(m(state).value), dispatch); + cancel: (state: StoreState, dispatch: Dispatch) => { + f(state).write(initialFormStateFromValue(m(state).value), state, dispatch); }, valid: (state: any): boolean => { return f(state).value.valid; diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 17c589131a..5d3e82b62d 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -1,27 +1,23 @@ import React from "react"; import { useSelector } from "react-redux"; import { AnyAction, Dispatch } from "redux"; -import { ArrayFieldElement, ArrayFieldState } from "../store/common"; -import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, StoreType, StoreTypes } from "./data"; +import { StoreState } from "../store/common"; +import { Schema } from "../utility/schema"; +import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, StoreType } from "./data"; +import { Dependency } from "./dependency"; export const CHandleFactory = React.createContext(undefined); -export abstract class DataHandle { - constructor(protected currentValue: V) { +export abstract class DataHandle { + constructor(protected currentValue: F) { this.value = currentValue; } - abstract write(value: V, dispatch: Dispatch); - readonly value: V; + abstract write(value: F, state: StoreState, dispatch: Dispatch); + readonly value: F; } -export abstract class ArrayDataHandle> extends DataHandle { - abstract append(element: ArrayFieldElement, dispatch: Dispatch); - abstract appendAt(index: number, element: ArrayFieldElement, dispatch: Dispatch); - abstract removeAt(index: number, dispatch: Dispatch); -} - -export interface EmptyDataHandle = DataHandle> { +export interface EmptyDataHandle = DataHandle> { /** * use the current state to populate the data in the handle without subscribing to updates * @param state current state @@ -33,88 +29,74 @@ export interface EmptyDataHandle = DataHandle> { hook(): D; } +export type SelectorUser = (selector: (state: any) => M) => M; + export abstract class HandleFactory { - abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; - abstract createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle; + constructor(protected schema: Schema) {} + abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; + //abstract createArrayHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; } export class BaseHandleFactory extends HandleFactory { - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { - let ms = getModelReadSelector(type)(dependency.modelName); - let mac = getModelWriteActionCreator(type); - let vs = getValueSelector(type); - let cdh = (value: V): DataHandle => { - return new (class extends DataHandle { - write = (value: V, dispatch: Dispatch) => { - dispatch(mac(dependency.modelName, value)); - } - })(value); - } - return { - initialize: (state: any) => { - return cdh(vs(ms(state))); - }, - hook: () => { - return cdh(vs(useSelector(ms))); - } - } - } - - createArrayHandle>(dependency: Dependency, type: StoreType): EmptyDataHandle> { - let ms = getModelReadSelector(type)(dependency.modelName); - let mac = getModelWriteActionCreator(type); - let vs = getValueSelector(type); - let cdh = (value: V): ArrayDataHandle => { - return new (class extends ArrayDataHandle { - write = (value: V, dispatch: Dispatch) => { - dispatch(mac(dependency.modelName, value)); - } - appendAt = (index: number, element: ArrayFieldElement, dispatch: Dispatch) => { - this.currentValue.splice(index, 0, element); - this.write(this.currentValue, dispatch); - } - append = (element: ArrayFieldElement, dispatch: Dispatch) => { - this.currentValue.push(element); - this.write(this.currentValue, dispatch); - } - removeAt = (index: number, dispatch: Dispatch) => { - this.currentValue.splice(index, 1); - this.write(this.currentValue, dispatch); + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + let ms = getModelReadSelector(type)(dependency.modelName); + let mac = getModelWriteActionCreator(type); + let cdh = (value: F): DataHandle => { + return new (class extends DataHandle { + write = (value: F, state: StoreState, dispatch: Dispatch) => { + let mv = {...state[type.name][dependency.modelName]}; + mv[dependency.fieldName] = value; + dispatch(mac(dependency.modelName, mv)); } })(value); } return { initialize: (state: any) => { - return cdh(vs(ms(state))); + return cdh(ms(state)[dependency.fieldName]); }, hook: () => { - return cdh(vs(useSelector(ms))); + return cdh(useSelector(ms)[dependency.fieldName]); } } } } -export type DependencyValues = { - getValues: () => F[] -} - /** * Read-only alternative to handles that supports wildcards */ export class DependencyReader { - constructor(private dependencies: Dependency[], private type: StoreType) { + constructor(private dependencies: Dependency[], private type: StoreType, private schema: Schema) { } - hook = (): DependencyValues => { - let vs = getModelReadSelector(this.type) + private expandWildcard(dependency: Dependency): Dependency[] { + if(dependency.fieldName === `*`) { + return Object.keys(this.schema.models[dependency.fieldName]).map(fName => new Dependency(`${dependency.modelName}.${fName}`)); + } + return [dependency]; + } + hook = (): any[] => { + let vs = getValueSelector(this.type); + return this.dependencies.flatMap(d => { + let c = (d: Dependency) => { + let ms = getModelReadSelector(this.type)(d.modelName); + return useSelector(ms)[d.fieldName]; + } - let ms = getModelReadSelector(this.type)(dependency.modelName); - + return this.expandWildcard(d).map(d => vs(c(d))); + }) } - initialize = (state: any): DependencyValues => { + initialize = (state: any): any[] => { + let vs = getValueSelector(this.type); + return this.dependencies.flatMap(d => { + let c = (d: Dependency) => { + let ms = getModelReadSelector(this.type)(d.modelName); + return ms(state)[d.fieldName]; + } + return this.expandWildcard(d).map(d => vs(c(d))); + }) } } diff --git a/react/src/hook/shown.ts b/react/src/hook/shown.ts index 49d63bff8b..79c19ed0fa 100644 --- a/react/src/hook/shown.ts +++ b/react/src/hook/shown.ts @@ -1,9 +1,9 @@ import { useContext } from "react"; -import { StoreTypes } from "../data/data"; +import { StoreType, StoreTypes } from "../data/data"; import { CHandleFactory } from "../data/handle"; import { interpolate } from "../utility/string" -export function useShown(shownStr: string, defaultValue: boolean, type: StoreTypes) { +export function useShown(shownStr: string, defaultValue: boolean, type: StoreType) { let dhf = useContext(CHandleFactory); if(shownStr) { let shown = interpolate(shownStr).withDependencies(dhf, type).evaluated(); diff --git a/react/src/layout/arrange/stack.tsx b/react/src/layout/arrange/stack.tsx index 1e5f47b673..52026ea55a 100644 --- a/react/src/layout/arrange/stack.tsx +++ b/react/src/layout/arrange/stack.tsx @@ -24,10 +24,6 @@ export abstract class BaseStack extends Layout { }); } - - getFormDependencies(): Dependency[] { - return (this.children || []).flatMap(c => c.getFormDependencies()); - } } diff --git a/react/src/layout/arrange/waterfall.tsx b/react/src/layout/arrange/waterfall.tsx index d44098632c..9ee1e67e5d 100644 --- a/react/src/layout/arrange/waterfall.tsx +++ b/react/src/layout/arrange/waterfall.tsx @@ -46,11 +46,6 @@ export class WaterfallLayout extends Layout { return bins; } - - - getFormDependencies(): Dependency[] { - return (this.children || []).flatMap(c => c.getFormDependencies()); - } getMarginStyles = (): string => { if(!this.config.gutters) { diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index cc14564540..46473fe07f 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -1,19 +1,19 @@ import React, { useContext, useState } from "react"; import { FunctionComponent } from "react"; import { Container, Modal } from "react-bootstrap"; -import { useStore } from "react-redux"; +import { useDispatch, useStore } from "react-redux"; import { formActionFunctions } from "../component/reusable/form"; import { ViewPanelActionButtons } from "../component/reusable/panel"; -import { ModelsAccessor } from "../data/accessor"; -import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { ArrayAliases, HandleFactoryWithArrayAliases } from "../data/alias"; +import { CAppWrapper, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { newModelFromSchema, StoreTypes } from "../data/data"; import { Dependency } from "../data/dependency"; -import { CFormController, formStateFromModel } from "../data/formController"; -import { AbstractModelsWrapper, CFormStateWrapper, CModelsWrapper, ModelAliases, ModelHandle, ModelsWrapper, ModelsWrapperWithAliases } from "../data/wrapper"; +import { formStateFromModelState, FormStateHandleFactory } from "../data/form"; +import { CHandleFactory } from "../data/handle"; +import { ArrayFieldState } from "../store/common"; import { FormFieldState, FormModelState } from "../store/formState"; import { CRouteHelper } from "../utility/route"; import { Schema, SchemaLayout } from "../utility/schema"; -import { AliasedFormControllerWrapper, FormControllerAliases, FormControllerElement } from "./form"; -import { ArrayField, ArrayModelElement } from "./input/array"; import { Layout, LayoutProps } from "./layout"; import { createLayouts } from "./layouts"; @@ -44,16 +44,22 @@ export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: let { baseElement, onClick, modalShown, onHideModal } = props; let routeHelper = useContext(CRouteHelper); - let formController = useContext(CFormController); let store = useStore(); let simulationInfoPromise = useContext(CSimulationInfoPromise); - let modelsWrapper = useContext(CModelsWrapper); - let schema = useContext(CSchema); - - let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); - - let isDirty = formController.isFormStateDirty(); - let isValid = formController.isFormStateValid(); + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + let dispatch = useDispatch(); + let appWrapper = useContext(CAppWrapper); + + let { submit: _submit, cancel: _cancel } = formActionFunctions({ + formHandleFactory, + store, + simulationInfoPromise, + appWrapper, + dispatch + }); + + let isDirty = formHandleFactory.isDirty(); + let isValid = formHandleFactory.isValid(store.getState()); let actionButtons = return ( <> @@ -89,49 +95,47 @@ export class BeamlineLayout extends Layout { this.elements = config.elements.map(e => createLayouts(e, "items")); } - getFormDependencies(): Dependency[] { - return [new Dependency(this.config.beamlineDependency)]; - } - component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { console.log("RENDER BEAMLINE"); let routeHelper = useContext(CRouteHelper); - let formStateWrapper = useContext(CFormStateWrapper); - let modelsWrapper = useContext(CModelsWrapper); - let formController = useContext(CFormController); let store = useStore(); let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); + let dispatch = useDispatch(); + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + let appWrapper = useContext(CAppWrapper); let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); let [shownModal, updateShownModal] = useState(undefined); - let accessor = new ModelsAccessor(formStateWrapper, [beamlineDependency]); - - let beamlineValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; + let handle = formHandleFactory.createHandle>>(beamlineDependency, StoreTypes.FormState).hook(); // TODO: form or model? let addBeamlineElement = (element: BeamlineElement) => { console.log("AAA"); let ms = schema.models[element.model]; // TODO: use generic methods - let prev: FormModelState | undefined = beamlineValue.length > 0 ? beamlineValue[beamlineValue.length - 1].item : undefined + let l = handle.value.value.length; + let prev: FormModelState | undefined = l > 0 ? handle.value.value[l - 1].item : undefined let nextPosition: string = prev ? `${parseFloat(prev.position.value) + 5}` : "0"; let nextId: string = prev ? `${parseInt(prev.id.value) + 1}` : "1"; - let mv = formStateFromModel({ + let mv = newModelFromSchema(ms, { id: nextId, position: nextPosition, type: element.model - }, ms, schema); + }) + console.log("new beamline element mv", mv); - let bv = [...beamlineValue]; + let bv = [...handle.value.value]; bv.push({ - item: mv, + item: formStateFromModelState(mv), model: element.model }); - let m = formStateWrapper.getModel(beamlineDependency.modelName, store.getState()); - m = formStateWrapper.setFieldInModel(beamlineDependency.fieldName, m, bv as any as FormFieldState); - formStateWrapper.updateModel(beamlineDependency.modelName, m, store.getState()); + handle.write({ + ...handle.value, + touched: true, + value: bv + }, store.getState()[StoreTypes.FormState.name], dispatch); console.log("ADD ELEMENT"); } @@ -151,37 +155,42 @@ export class BeamlineLayout extends Layout { console.log("MAPPING BEAMLINE ELEMENTS"); - let beamlineComponents = beamlineValue.map((e, i) => { + let beamlineComponents = handle.value.value.map((e, i) => { let model = e.model; let ele: FormModelState = e.item; let id = ele.id.value; console.log("id", id); let baseElement = findBaseElementByModel(model); - let deps = baseElement.layouts.flatMap(l => l.getFormDependencies()); - let aliases: FormControllerAliases = [ + let aliases: ArrayAliases = [ { - real: { + realDataLocation: { modelName: beamlineDependency.modelName, fieldName: beamlineDependency.fieldName, index: i }, - fake: model, - realSchemaName: model + realSchemaName: model, + fake: model } ]; + + let aliasedHandleFactory = new HandleFactoryWithArrayAliases(schema, aliases, formHandleFactory); return ( - - - updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> - - + + updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> + ) }) - let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); + let { submit: _submit, cancel: _cancel } = formActionFunctions({ + formHandleFactory, + store, + simulationInfoPromise, + appWrapper, + dispatch + }); - let isDirty = formController.isFormStateDirty(); - let isValid = formController.isFormStateValid(); + let isDirty = formHandleFactory.isDirty(); + let isValid = formHandleFactory.isValid(store.getState()); let actionButtons = return ( diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index b4db583511..2f907e00b1 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -8,7 +8,7 @@ import { import { Dependency } from "../data/dependency"; import { FieldInput, LabeledFieldInput } from "../component/reusable/input"; import { useShown } from "../hook/shown"; -import { useDispatch } from "react-redux"; +import { useDispatch, useStore } from "react-redux"; import { CSchema } from "../data/appwrapper"; import { FormStateHandleFactory } from "../data/form"; import { CHandleFactory } from "../data/handle"; @@ -17,9 +17,10 @@ import { FormFieldState } from "../store/formState"; export function FormControllerElement(props: {children?: React.ReactNode}) { let schema = useContext(CSchema); - let formHandleFactory = new FormStateHandleFactory(schema); - formHandleFactory.useUpdates(); + let handleFactory = useContext(CHandleFactory); + let formHandleFactory = new FormStateHandleFactory(schema, handleFactory); // TODO: form controller might need to "subscribe to updates" during save + formHandleFactory.useUpdates(); return ( @@ -61,18 +62,11 @@ export type FieldGridConfig = { } export class FieldGridLayout extends Layout { - getFormDependencies = () => { - let fields = []; - for(let row of this.config.rows) { - fields.push(...(row.fields)); - } - return fields.map(f => new Dependency(f)); - } - component = (props: LayoutProps<{}>) => { let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let schema = useContext(CSchema); let dispatch = useDispatch(); + let store = useStore(); let gridShown = useShown(this.config.shown, true, StoreTypes.FormState); if (! gridShown) { @@ -102,7 +96,7 @@ export class FieldGridLayout extends Layout { {labelElement ? {labelElement} : undefined} {columns.map((_, index) => { let fieldDependency = new Dependency(fields[index]); - let fieldHandle = formHandleFactory.createHandle>(fieldDependency, StoreTypes.FormState).hook(); + let fieldHandle = formHandleFactory.createHandle(fieldDependency, StoreTypes.FormState).hook(); let fieldType = schema.models[fieldDependency.modelName][fieldDependency.fieldName].type; return ( { valid: fieldType.validate(value), touched: true, value - }, dispatch) + }, store.getState()[StoreTypes.FormState.name], dispatch) }} dependency={fieldDependency} inputComponent={fieldType.component}/> @@ -137,21 +131,18 @@ export class FieldListLayout extends Layout { super(config); } - getFormDependencies = () => { - return (this.config.fields || []).map(f => new Dependency(f)); - } - component = (props: LayoutProps<{}>) => { let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let schema = useContext(CSchema); let dispatch = useDispatch(); + let store = useStore(); let fields = this.config.fields; return <> {fields.map((fieldDepString, idx) => { let fieldDep = new Dependency(fieldDepString); - let fieldHandle = formHandleFactory.createHandle>(fieldDep, StoreTypes.FormState).hook(); + let fieldHandle = formHandleFactory.createHandle(fieldDep, StoreTypes.FormState).hook(); let fieldType = schema.models[fieldDep.modelName][fieldDep.fieldName].type; let fieldSchema = schema.models[fieldDep.modelName][fieldDep.fieldName]; let shown = useShown(fieldSchema.shown, true, StoreTypes.FormState); @@ -168,7 +159,7 @@ export class FieldListLayout extends Layout { valid: fieldType.validate(value), touched: true, value - }, dispatch) + }, store.getState()[StoreTypes.FormState.name], dispatch) }} inputComponent={fieldSchema.type.component}/> } diff --git a/react/src/layout/input/enum.tsx b/react/src/layout/input/enum.tsx index 4b54008a36..b5ad95bd1f 100644 --- a/react/src/layout/input/enum.tsx +++ b/react/src/layout/input/enum.tsx @@ -8,7 +8,7 @@ import { InputComponentProps, InputConfigBase, InputLayout } from "./input"; import { LayoutProps } from "../layout"; import { pollStatefulCompute } from "../../utility/compute"; import { CHandleFactory } from "../../data/handle"; -import { StoreTypes } from "../../data/data"; +import { getValueSelector, StoreTypes } from "../../data/data"; export type EnumAllowedValues = { value: string, displayName: string }[] @@ -120,8 +120,8 @@ export class SimulationListEnumInputLayout extends EnumInputBaseLayout { if (! simType) { diff --git a/react/src/layout/input/file.tsx b/react/src/layout/input/file.tsx index 9217d5c34d..83df7724aa 100644 --- a/react/src/layout/input/file.tsx +++ b/react/src/layout/input/file.tsx @@ -4,8 +4,7 @@ import React, { ChangeEventHandler, useEffect, useRef } from "react"; import { FunctionComponent, useContext, useState } from "react"; import { Button, Form, Modal } from "react-bootstrap"; import { CAppName, CSimulationInfoPromise } from "../../data/appwrapper"; -import { CModelsWrapper } from "../../data/wrapper"; -import { interpolate, ValueSelectors } from "../../utility/string"; +import { interpolate } from "../../utility/string"; import { downloadAs } from "../../utility/download"; import { SchemaLayout } from "../../utility/schema"; import { LayoutProps } from "../layout"; @@ -13,6 +12,8 @@ import { LAYOUTS } from "../layouts"; import { InputComponentProps, InputConfigBase, InputLayout } from "./input"; import "./file.scss"; import { CRouteHelper } from "../../utility/route"; +import { CHandleFactory } from "../../data/handle"; +import { StoreTypes } from "../../data/data"; export type FileInputConfig = { pattern: string, @@ -35,7 +36,7 @@ export class FileInputLayout extends InputLayout }), - title: interpolate(this.config.inspectModal.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw() + title: interpolate(this.config.inspectModal.title).withDependencies(handleFactory, StoreTypes.Models).raw() } : undefined; let [fileNameList, updateFileNameList] = useState(undefined); diff --git a/react/src/layout/input/input.tsx b/react/src/layout/input/input.tsx index ad107e1bfa..0cdd07d689 100644 --- a/react/src/layout/input/input.tsx +++ b/react/src/layout/input/input.tsx @@ -17,11 +17,6 @@ export type InputConfigBase = { export type InputLayoutType = any> = new(config: C) => L export abstract class InputLayout extends Layout> { - - getFormDependencies(): Dependency[] { - return []; - } - abstract toModelValue: (value: V) => M; abstract fromModelValue: (value: M) => V; diff --git a/react/src/layout/layout.ts b/react/src/layout/layout.ts index 4222256cd4..e4ff69f95c 100644 --- a/react/src/layout/layout.ts +++ b/react/src/layout/layout.ts @@ -9,10 +9,8 @@ export abstract class Layout { name: string; constructor(protected config: C) { - this.name = this.constructor.name; // this probably will always return 'Layout' with typescript + this.name = this.constructor.name; // TODO: this probably will always return 'Layout' with typescript } - abstract getFormDependencies(): Dependency[]; - component: React.FunctionComponent>; } diff --git a/react/src/layout/missing.tsx b/react/src/layout/missing.tsx index 2d3c5666cd..859609e6eb 100644 --- a/react/src/layout/missing.tsx +++ b/react/src/layout/missing.tsx @@ -2,10 +2,6 @@ import React from "react"; import { Layout } from "./layout"; export class MissingLayout extends Layout { - getFormDependencies = () => { - return []; - } - component = (props) => { return <>Missing layout!; } diff --git a/react/src/layout/multipanel.tsx b/react/src/layout/multipanel.tsx index 48c007c23e..873d2364c2 100644 --- a/react/src/layout/multipanel.tsx +++ b/react/src/layout/multipanel.tsx @@ -26,10 +26,6 @@ export class MultiPanelLayout extends Layout { this.items = config.items.map(LAYOUTS.getLayoutForSchema); } - getFormDependencies = () => { - return [...(this.items)].map(childLayout => childLayout.getFormDependencies()).flat(); - } - component = (props: LayoutProps<{}>) => { let { reportName, reportGroupName, frameIdFields } = this.config; let modelsWrapper = useContext(CModelsWrapper); diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index 5ec3f6da82..5b66c8d47b 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -1,22 +1,23 @@ import { Nav , Modal, Col, Row } from "react-bootstrap"; import { Navigate, useRoutes, Link, useResolvedPath, useParams } from "react-router-dom"; import { NavbarLeftContainerId, NavbarRightContainerId } from "../component/reusable/navbar"; -import { interpolate, ValueSelectors } from "../utility/string"; +import { interpolate } from "../utility/string"; import { useContext, useState } from "react"; import { LayoutProps, Layout } from "./layout"; -import { useStore } from "react-redux"; +import { useDispatch, useStore } from "react-redux"; import { ViewPanelActionButtons } from "../component/reusable/panel"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; import { CRelativeRouterHelper, RelativeRouteHelper } from "../utility/route"; import React from "react"; -import { CFormController } from "../data/formController"; -import { CModelsWrapper, ModelsWrapper } from "../data/wrapper"; -import { CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { CAppWrapper, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; import { Portal } from "../component/reusable/portal"; import { formActionFunctions } from "../component/reusable/form"; +import { CHandleFactory } from "../data/handle"; +import { StoreTypes } from "../data/data"; +import { FormStateHandleFactory } from "../data/form"; export type NavBarModalButtonConfig = { modal: { @@ -38,35 +39,32 @@ export class NavBarModalButton extends Layout { }); } - getFormDependencies = () => { - return this.children.map(child => child.getFormDependencies()).flat(); - } - component = (props: LayoutProps<{}>) => { - let formController = useContext(CFormController); let simulationInfoPromise = useContext(CSimulationInfoPromise); - let modelsWrapper = useContext(CModelsWrapper); - - let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); - let modalTitle = interpolate(this.config.modal.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); - + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let [modalShown, updateModalShown] = useState(false); - - let schema = useContext(CSchema); - - - + let dispatch = useDispatch(); let store = useStore(); + let appWrapper = useContext(CAppWrapper); + + let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); + let modalTitle = interpolate(this.config.modal.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); - let { submit: _submit, cancel: _cancel } = formActionFunctions(formController, store, simulationInfoPromise, schema, modelsWrapper as ModelsWrapper); + let { submit: _submit, cancel: _cancel } = formActionFunctions({ + formHandleFactory, + store, + simulationInfoPromise, + appWrapper, + dispatch + }); let children = this.children.map((child, idx) => { let LayoutElement = child.component; return }) - let isDirty = formController.isFormStateDirty(); - let isValid = formController.isFormStateValid(); + let isDirty = formHandleFactory.isDirty(); + let isValid = formHandleFactory.isValid(store.getState()); let actionButtons = let { icon } = this.config; @@ -129,11 +127,6 @@ export class NavTabsLayout extends Layout { }) } - getFormDependencies = () => { - // TODO - return []; - } - TabsContent = (props: { tab: NavTabWithLayouts }) => { let { tab, ...otherProps } = props; @@ -151,8 +144,7 @@ export class NavTabsLayout extends Layout { TabsSwitcher = (props: LayoutProps<{}>) => { let { tabName: selectedTabName } = useParams(); - - let modelsWrapper = useContext(CModelsWrapper); + let handleFactory = useContext(CHandleFactory); let routerHelper = useContext(CRelativeRouterHelper); return ( @@ -165,7 +157,7 @@ export class NavTabsLayout extends Layout { return ( - {interpolate(tab.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw()} + {interpolate(tab.title).withDependencies(handleFactory, StoreTypes.Models).raw()} ) diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 07751a7325..17cd6ee432 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -31,10 +31,6 @@ export class PanelLayout extends Layout { this.advanced = (!!config.advanced) ? config.advanced.map(LAYOUTS.getLayoutForSchema) : undefined; } - getFormDependencies = () => { - return [...(this.basic || []), ...(this.advanced || [])].map(childLayout => childLayout.getFormDependencies()).flat(); - } - component = (props: LayoutProps<{}>) => { let simulationInfoPromise = useContext(CSimulationInfoPromise); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index f8f71e4cc0..24037d877f 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -17,7 +17,7 @@ import { SchemaLayout } from "../utility/schema"; import { CRouteHelper } from "../utility/route"; import { ModelState } from "../store/models"; import { useShown } from "../hook/shown"; -import { CHandleFactory } from "../data/handle"; +import { CHandleFactory, DependencyReader } from "../data/handle"; import { StoreTypes, ValueSelectors } from "../data/data"; import { FormFieldState } from "../store/formState"; @@ -43,20 +43,17 @@ export class AutoRunReportLayout extends Layout { this.reportLayout = LAYOUTS.getLayoutForSchema(config.reportLayout) as ReportVisual; } - getFormDependencies = () => { - return this.reportLayout.getFormDependencies(); - } - component = (props: LayoutProps<{}>) => { let { report, dependencies } = this.config; let simulationInfoPromise = useContext(CSimulationInfoPromise); let appName = useContext(CAppName); + let schema = useContext(CSchema); let routeHelper = useContext(CRouteHelper); let handleFactory = useContext(CHandleFactory); let reportDependencies = dependencies.map(dependencyString => new Dependency(dependencyString)); - let dependentValues = reportDependencies.map(d => ValueSelectors.Form(handleFactory.createHandle(d, StoreTypes.FormState).hook().value as FormFieldState)); + let dependentValues = new DependencyReader(reportDependencies, StoreTypes.Models, schema).hook(); let [simulationData, updateSimulationData] = useState(undefined); let simulationPollingVersionRef = useRef(uuidv4()) @@ -180,10 +177,6 @@ export class ManualRunReportLayout extends Layout { this.reportLayout = LAYOUTS.getLayoutForSchema(config.reportLayout) as ReportVisual; } - getFormDependencies = () => { - return this.reportLayout.getFormDependencies(); - } - component = (props: LayoutProps<{}>) => { let { reportName, reportGroupName, frameIdFields } = this.config; let showAnimationController = 'showAnimationController' in this.config @@ -312,11 +305,7 @@ export class SimulationStartLayout extends Layout { this.childLayouts = (config.items || []).map(LAYOUTS.getLayoutForSchema); } - - getFormDependencies = () => { - return (this.childLayouts || []).flatMap(v => v.getFormDependencies()); - } - + component = (props: LayoutProps<{}>) => { let { reportGroupName } = this.config; diff --git a/react/src/layout/report/graph2d.tsx b/react/src/layout/report/graph2d.tsx index 10fe0ce02d..98ca7d6a9b 100644 --- a/react/src/layout/report/graph2d.tsx +++ b/react/src/layout/report/graph2d.tsx @@ -77,10 +77,6 @@ export class Graph2dFromApi extends ReportVisual { - return []; - } - component = (props: LayoutProps<{}> & ReportVisualProps) => { let { data, model } = props; if(!data) { diff --git a/react/src/layout/report/heatplot.tsx b/react/src/layout/report/heatplot.tsx index ef2a5ec848..468e2ddd3e 100644 --- a/react/src/layout/report/heatplot.tsx +++ b/react/src/layout/report/heatplot.tsx @@ -58,10 +58,6 @@ export class HeatplotFromApi extends ReportVisual { - return []; - } - component = (props: LayoutProps<{}> & ReportVisualProps) => { let { data, model } = props; diff --git a/react/src/layout/report/histogram2d.tsx b/react/src/layout/report/histogram2d.tsx index fb3692c164..0e3af527da 100644 --- a/react/src/layout/report/histogram2d.tsx +++ b/react/src/layout/report/histogram2d.tsx @@ -66,10 +66,6 @@ export class Histogram2dFromApi extends ReportVisual { - return []; - } - component = (props: LayoutProps<{}> & ReportVisualProps) => { let { data, model } = props; if(!data) { diff --git a/react/src/layout/report/table.tsx b/react/src/layout/report/table.tsx index b911a0b3bc..17b4d4e1fe 100644 --- a/react/src/layout/report/table.tsx +++ b/react/src/layout/report/table.tsx @@ -45,10 +45,6 @@ export class TableFromApi extends ReportVisual { - return []; - } - component = (props: LayoutProps<{}> & ReportVisualProps) => { let { data } = props; diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index 2ddc14e901..fa75888162 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -16,10 +16,6 @@ export type BeamlineWatchpointReportsConfig = { } export class BeamlineWatchpointReports extends Layout { - getFormDependencies(): Dependency[] { - return []; - } - component: FunctionComponent<{ [key: string]: any; }> = (props) => { let watchpointReportsDependency = new Dependency(this.config.watchpointReportsDependency); let beamlineDependency = new Dependency(this.config.beamlineDependency); diff --git a/react/src/layout/tabs.tsx b/react/src/layout/tabs.tsx index ee4d942555..1002735c82 100644 --- a/react/src/layout/tabs.tsx +++ b/react/src/layout/tabs.tsx @@ -36,18 +36,6 @@ export class TabLayout extends Layout { }) } - getFormDependencies = () => { - let fields = []; - - for (let tab of this.tabs) { - for (let layout of tab.layouts) { - fields.push(...layout.getFormDependencies()); - } - } - - return fields; - } - component = (props: LayoutProps<{}>) => { let tabEls = []; diff --git a/react/src/layout/text.tsx b/react/src/layout/text.tsx index c46681c5fc..994ae8a60c 100644 --- a/react/src/layout/text.tsx +++ b/react/src/layout/text.tsx @@ -15,10 +15,6 @@ export type TextConfig = { } export class TextLayout extends Layout { - getFormDependencies(): Dependency[] { - return []; - } - component: FunctionComponent<{ [key: string]: any; }> = (props) => { let modelsWrapper = useContext(CModelsWrapper); diff --git a/react/src/utility/compute.ts b/react/src/utility/compute.ts index 368b93ae74..d70218d730 100644 --- a/react/src/utility/compute.ts +++ b/react/src/utility/compute.ts @@ -1,4 +1,5 @@ -import { ModelStates } from "../store/models"; +import { StoreState } from "../store/common"; +import { ModelState } from "../store/models"; import { RouteHelper } from "./route"; export type SrState = 'completed' | 'srException' | 'error' | 'running' | 'pending' | 'canceled' | 'missing'; @@ -61,7 +62,7 @@ export function pollStatefulCompute(routeHelper: RouteHelper, { method, simulati export type ReportComputeParams = { forceRun: boolean - models: ModelStates, + models: StoreState, report: string } & StatefulComputeParams @@ -97,7 +98,7 @@ export function pollRunReport(routeHelper: RouteHelper, { appName, models, simul export type CancelComputeParams = { appName: string, - models: ModelStates, + models: StoreState, simulationId: string, report: string } @@ -120,7 +121,7 @@ export function cancelReport(routeHelper: RouteHelper, { appName, models, simula export type RunStatusParams = { appName: string, - models: ModelStates, + models: StoreState, simulationId: string, report: string, forceRun: boolean diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 9a03417238..48ebcf5432 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -1,4 +1,4 @@ -import { getValueSelector, StoreTypes } from "../data/data"; +import { getValueSelector, StoreType, StoreTypes } from "../data/data"; import { Dependency } from "../data/dependency"; import { HandleFactory } from "../data/handle"; @@ -36,7 +36,7 @@ export class InterpolationBase { ) } - withDependencies(handleFactory: HandleFactory, type: StoreTypes): InterpolationResult { + withDependencies(handleFactory: HandleFactory, type: StoreType): InterpolationResult { let valueSelector = getValueSelector(type) as (v: F) => any; let mappingsArr = this.matches.map(([originalString, mappedGroup]) => { From 1a5f711e9fe18ece23fb22fdd96b849ebcb6ebdd Mon Sep 17 00:00:00 2001 From: garsuga Date: Mon, 10 Apr 2023 22:09:16 +0000 Subject: [PATCH 24/68] wip debug data changes --- react/src/component/reusable/form.tsx | 12 +- react/src/component/reusable/panel.tsx | 6 +- react/src/component/simulation.tsx | 56 ++- react/src/data/form.ts | 2 + react/src/data/handle.ts | 47 +- react/src/layout/form.tsx | 1 - react/src/layout/multipanel.tsx | 9 +- react/src/layout/report.tsx | 18 +- .../shadow/beamlineWatchpointReports.tsx | 45 +- react/src/layout/tabs.tsx | 8 +- react/src/layout/text.tsx | 10 +- react/src/store/common.ts | 2 +- react/src/utility/string.ts | 2 +- react/utility/convertschema.ts | 426 ------------------ 14 files changed, 129 insertions(+), 515 deletions(-) delete mode 100644 react/utility/convertschema.ts diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 43b5efbc8a..46339edc35 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -13,12 +13,13 @@ import { formStatesSlice, initialFormStateFromValue } from "../../store/formState"; -import { useStore } from "react-redux"; +import { useDispatch, useStore } from "react-redux"; import { AppWrapper, CSchema } from "../../data/appwrapper"; import { SimulationInfo } from "../simulation"; import { AnyAction, Dispatch, Store } from "redux"; import { FormStateHandleFactory } from "../../data/form"; -import { modelsSlice } from "../../store/models"; +import { modelActions, modelsSlice } from "../../store/models"; +import { mapProperties } from "../../utility/object"; export function FormField(props) { let { label, tooltip, ...passedProps } = props; @@ -76,6 +77,7 @@ export function FormStateInitializer(props) { let schema = useContext(CSchema); let store = useStore(); + let dispatch = useDispatch(); let ms = store.getState()[modelsSlice.name] let fs = store.getState()[formStatesSlice.name]; @@ -96,9 +98,11 @@ export function FormStateInitializer(props) { if(!modelSchema) { throw new Error(`could not get schema for model=${modelName}`); } - fs[modelName] = mapProperties(ms, ([_, fv]) => initialFormStateFromValue(fv)); + dispatch(modelActions.updateModel({ + name: modelName, + value: mapProperties(ms, ([_, fv]) => initialFormStateFromValue(fv)) + })); }); - updateHasInit(true); }, []) diff --git a/react/src/component/reusable/panel.tsx b/react/src/component/reusable/panel.tsx index 62308651a9..528334fce2 100644 --- a/react/src/component/reusable/panel.tsx +++ b/react/src/component/reusable/panel.tsx @@ -4,17 +4,13 @@ import { Button, Modal } from "react-bootstrap"; -import React, { useState, Fragment, useContext } from "react"; +import React, { useState, Fragment } from "react"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; import { EditorForm } from "./form"; import { v4 as uuidv4 } from 'uuid'; import { CPanelController } from "../../data/panel" import { PanelController } from "../../data/panel"; -import { CFormController } from "../../data/formController"; -import { useStore } from "react-redux"; -import { CSchema, CSimulationInfoPromise } from "../../data/appwrapper"; -import { CModelsWrapper, ModelsWrapper } from "../../data/wrapper"; export function Panel(props) { let { title, buttons, panelBodyShown } = props; diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index cee71bec14..3102839b7c 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -45,9 +45,7 @@ export type SimulationInfo = SimulationInfoRaw & { simulationId: string } -function SimulationInfoInitializer(props: { simulationId: string } & {[key: string]: any}) { - let { simulationId } = props; - +function SimulationStoreInitializer(props: {[key: string]: any}) { const modelsStore = configureStore({ // TODO: this belongs on the simulation root component reducer: { [modelsSlice.name]: modelsSlice.reducer, @@ -55,6 +53,18 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri }, }); + return ( + + {props.children} + + ) +} + +function SimulationInfoInitializer(props: { simulationId: string } & {[key: string]: any}) { + let { simulationId } = props; + + + let [simulationInfoPromise, updateSimulationInfoPromise] = useState(undefined); let [hasInit, updateHasInit] = useState(false); let appName = useContext(CAppName); @@ -62,6 +72,8 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let routeHelper = useContext(CRouteHelper); let dispatch = useDispatch(); + console.log("modelActions", modelActions); + useEffect(() => { updateSimulationInfoPromise(new Promise((resolve, reject) => { fetch(routeHelper.globalRoute("simulationData", { @@ -86,13 +98,11 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri }, []) return hasInit && simulationInfoPromise && ( - - - - {props.children} - - - + + + {props.children} + + ) } @@ -289,17 +299,19 @@ export function SimulationRoot(props: {simulationId: string}) { // TODO: use multiple rows return ( - - - - - - - - {layoutComponents} - - - - + + + + + + + + + {layoutComponents} + + + + + ) } diff --git a/react/src/data/form.ts b/react/src/data/form.ts index d19d3e89f8..f681d0dfe1 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -3,8 +3,10 @@ import { Dispatch, AnyAction, Store } from "redux"; import { StoreState } from "../store/common"; import { FormModelState, initialFormStateFromValue } from "../store/formState"; import { ModelState } from "../store/models"; +import { mapProperties } from "../utility/object"; import { Schema } from "../utility/schema"; import { StoreType, StoreTypes } from "./data"; +import { Dependency } from "./dependency"; import { BaseHandleFactory, DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; type FormActionFunc = (state: any, dispatch: Dispatch) => void diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 5d3e82b62d..3c87e1898b 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -1,9 +1,10 @@ import React from "react"; -import { useSelector } from "react-redux"; +import { useSelector, useStore } from "react-redux"; import { AnyAction, Dispatch } from "redux"; import { StoreState } from "../store/common"; +import { ModelState } from "../store/models"; import { Schema } from "../utility/schema"; -import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, StoreType } from "./data"; +import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, StoreType, StoreTypes } from "./data"; import { Dependency } from "./dependency"; export const CHandleFactory = React.createContext(undefined); @@ -61,6 +62,11 @@ export class BaseHandleFactory extends HandleFactory { } } +export type DependencyValuePair = { + dependency: Dependency, + value: V +}; + /** * Read-only alternative to handles that supports wildcards */ @@ -76,27 +82,52 @@ export class DependencyReader { return [dependency]; } - hook = (): any[] => { + hook = (): DependencyValuePair[] => { let vs = getValueSelector(this.type); - return this.dependencies.flatMap(d => { + let newDeps = this.dependencies.flatMap(d => this.expandWildcard(d)); + + return newDeps.map(d => { let c = (d: Dependency) => { let ms = getModelReadSelector(this.type)(d.modelName); return useSelector(ms)[d.fieldName]; } - return this.expandWildcard(d).map(d => vs(c(d))); + return { + value: vs(c(d)), + dependency: d + } }) } - initialize = (state: any): any[] => { + initialize = (state: any): DependencyValuePair[] => { let vs = getValueSelector(this.type); - return this.dependencies.flatMap(d => { + let newDeps = this.dependencies.flatMap(d => this.expandWildcard(d)); + + return newDeps.map(d => { let c = (d: Dependency) => { let ms = getModelReadSelector(this.type)(d.modelName); return ms(state)[d.fieldName]; } - return this.expandWildcard(d).map(d => vs(c(d))); + return { + value: vs(c(d)), + dependency: d + } }) } } + + +export function useModelValue(modelName: string, type: StoreType): M { + let ms = getModelReadSelector(type); + return useSelector(ms(modelName)) + + /*return Object.fromEntries(new DependencyReader([new Dependency(`${modelName}.*`)], StoreTypes.Models, schema).hook().map(pair => { + return [ + pair.dependency.fieldName, + pair.value + ] + }));*/ + + +} diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index 2f907e00b1..ebc6cef000 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -13,7 +13,6 @@ import { CSchema } from "../data/appwrapper"; import { FormStateHandleFactory } from "../data/form"; import { CHandleFactory } from "../data/handle"; import { StoreTypes } from "../data/data"; -import { FormFieldState } from "../store/formState"; export function FormControllerElement(props: {children?: React.ReactNode}) { let schema = useContext(CSchema); diff --git a/react/src/layout/multipanel.tsx b/react/src/layout/multipanel.tsx index 873d2364c2..2a3d957267 100644 --- a/react/src/layout/multipanel.tsx +++ b/react/src/layout/multipanel.tsx @@ -1,5 +1,4 @@ import React from "react"; -import { CModelsWrapper } from "../data/wrapper"; import { Col, Row } from "react-bootstrap"; import { LAYOUTS } from "./layouts"; import { LayoutProps, Layout } from "./layout"; @@ -7,8 +6,10 @@ import { Panel } from "../component/reusable/panel"; import { ReportAnimationController, useAnimationReader } from "./report" import { SchemaLayout } from "../utility/schema"; import { useContext } from "react"; -import { interpolate, ValueSelectors } from "../utility/string"; +import { interpolate } from "../utility/string"; import { useWindowSize } from "../hook/breakpoint"; +import { CHandleFactory } from "../data/handle"; +import { StoreTypes } from "../data/data"; export type MultiPanelConfig = { items: SchemaLayout[], @@ -28,8 +29,8 @@ export class MultiPanelLayout extends Layout { component = (props: LayoutProps<{}>) => { let { reportName, reportGroupName, frameIdFields } = this.config; - let modelsWrapper = useContext(CModelsWrapper); - let title = interpolate(this.config.title).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); + let handleFactory = useContext(CHandleFactory); + let title = interpolate(this.config.title).withDependencies(handleFactory, StoreTypes.Models).raw(); // allow subplots to respond to window resize useWindowSize(); let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index 24037d877f..0eeddcb658 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -17,7 +17,7 @@ import { SchemaLayout } from "../utility/schema"; import { CRouteHelper } from "../utility/route"; import { ModelState } from "../store/models"; import { useShown } from "../hook/shown"; -import { CHandleFactory, DependencyReader } from "../data/handle"; +import { CHandleFactory, DependencyReader, useModelValue } from "../data/handle"; import { StoreTypes, ValueSelectors } from "../data/data"; import { FormFieldState } from "../store/formState"; @@ -182,11 +182,9 @@ export class ManualRunReportLayout extends Layout { let showAnimationController = 'showAnimationController' in this.config ? !!this.config.showAnimationController : true; - let handleFactory = useContext(CHandleFactory); - let store = useStore(); let shown = useShown(this.config.shown, true, StoreTypes.Models); //let model = getModelValues([reportName], modelsWrapper, store.getState())[reportName]; - let reportModel = // need to deal with * + let reportModel = useModelValue(reportName, StoreTypes.Models); let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); return ( <> @@ -201,7 +199,7 @@ export class ManualRunReportLayout extends Layout { return ( <> { - canShowReport && + canShowReport && } ) @@ -313,7 +311,6 @@ export class SimulationStartLayout extends Layout { let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); let simulationInfoPromise = useContext(CSimulationInfoPromise); - let modelsWrapper = useContext(CModelsWrapper); let schema = useContext(CSchema); let modelNames = Object.keys(schema.models); @@ -344,10 +341,9 @@ export class SimulationStartLayout extends Layout { useEffect(() => { // recover from previous runs on server simulationInfoPromise.then(({simulationId}) => { - let models = getModelValues(modelNames, modelsWrapper, store.getState()); reportEventManager.getRunStatusOnce({ appName, - models, + models: store.getState()[StoreTypes.Models.name], simulationId, report: reportGroupName }).then(simulationData => { @@ -357,7 +353,7 @@ export class SimulationStartLayout extends Layout { listenForReportData(); reportEventManager.pollRunStatus({ appName, - models, + models: store.getState()[StoreTypes.Models.name], simulationId, report: reportGroupName }) @@ -378,7 +374,7 @@ export class SimulationStartLayout extends Layout { simulationInfoPromise.then(({simulationId}) => { reportEventManager.startReport({ appName, - models: getModelValues(modelNames, modelsWrapper, store.getState()), + models: store.getState()[StoreTypes.Models.name], simulationId, report: reportGroupName }) @@ -393,7 +389,7 @@ export class SimulationStartLayout extends Layout { simulationInfoPromise.then(({simulationId}) => { cancelReport(routeHelper, { appName, - models: getModelValues(modelNames, modelsWrapper, store.getState()), + models: store.getState()[StoreTypes.Models.name], simulationId, report: reportGroupName }) diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index fa75888162..e66f4ee605 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -1,12 +1,12 @@ import React from "react"; import { FunctionComponent, useContext } from "react"; -import { ModelsAccessor } from "../../data/accessor"; +import { ArrayAliases, HandleFactoryWithArrayAliases } from "../../data/alias"; +import { CSchema } from "../../data/appwrapper"; +import { StoreTypes } from "../../data/data"; import { Dependency } from "../../data/dependency"; -import { CFormStateWrapper } from "../../data/wrapper"; -import { FormModelState } from "../../store/formState"; -import { SchemaLayout } from "../../utility/schema"; -import { AliasedFormControllerWrapper, FormControllerAliases } from "../form"; -import { ArrayField } from "../input/array"; +import { CHandleFactory } from "../../data/handle"; +import { ArrayFieldState } from "../../store/common"; +import { ModelState } from "../../store/models"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; @@ -19,40 +19,43 @@ export class BeamlineWatchpointReports extends Layout = (props) => { let watchpointReportsDependency = new Dependency(this.config.watchpointReportsDependency); let beamlineDependency = new Dependency(this.config.beamlineDependency); - let formStateWrapper = useContext(CFormStateWrapper); - let accessor = new ModelsAccessor(formStateWrapper, [watchpointReportsDependency, beamlineDependency]); - let reportsValue: ArrayField = accessor.getFieldValue(watchpointReportsDependency) as any as ArrayField; - let elementsValue: ArrayField = accessor.getFieldValue(beamlineDependency) as any as ArrayField; + let handleFactory = useContext(CHandleFactory); + let reportsHandle = handleFactory.createHandle(watchpointReportsDependency, StoreTypes.Models).hook(); + let elementsHandle = handleFactory.createHandle(beamlineDependency, StoreTypes.Models).hook(); + let reportsValue = reportsHandle.value as ArrayFieldState; + let elementsValue = elementsHandle.value as ArrayFieldState; + let schema = useContext(CSchema); - let findElementById = (id: number) => elementsValue.find(e => e.item.id.value === id); + let findElementById = (id: any) => elementsValue.find(e => e.item.id == id); - let reportElements = (reportsValue as any[]).map((report, index) => { - let id = report.item.id.value; + let reportElements = reportsValue.map((report, index) => { + let id = report.item.id; let ele = findElementById(id); - let position = ele.item.position.value; + let position = ele.item.position; let cfg = createPanelConfig(`watchpointReport${index}`, `Intensity Report, ${position}`); return { id: id, layout: LAYOUTS.getLayoutForSchema(cfg) } }).map((e, index) => { - let aliases: FormControllerAliases = [ + let aliases: ArrayAliases = [ { - real: { + realDataLocation: { modelName: watchpointReportsDependency.modelName, fieldName: watchpointReportsDependency.fieldName, index }, - fake: "watchpointReport", - realSchemaName: "watchpointReport" + realSchemaName: "watchpointReport", + fake: "watchpointReport" } ]; + let aliasedHandleFactory = new HandleFactoryWithArrayAliases(schema, aliases, handleFactory); let Comp = e.layout.component; return ( - - + + - + ) }) diff --git a/react/src/layout/tabs.tsx b/react/src/layout/tabs.tsx index 1002735c82..e78e87f076 100644 --- a/react/src/layout/tabs.tsx +++ b/react/src/layout/tabs.tsx @@ -1,12 +1,10 @@ -import { useContext } from "react"; import { LayoutProps, Layout } from "./layout"; import { Tab, Tabs } from "react-bootstrap"; import { useShown } from "../hook/shown"; import React from "react"; -import { CModelsWrapper } from "../data/wrapper"; -import { ValueSelectors } from "../utility/string"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; +import { StoreTypes } from "../data/data"; export type TabConfig = { items: SchemaLayout[], @@ -42,12 +40,10 @@ export class TabLayout extends Layout { let firstTabKey = undefined; - let modelsWrapper = useContext(CModelsWrapper); - for (let tabConfig of this.tabs) { let { name, shown: shownConfig, layouts } = tabConfig; - let shown = useShown(shownConfig, true, modelsWrapper, ValueSelectors.Models); + let shown = useShown(shownConfig, true, StoreTypes.Models); let layoutElements = layouts.map((layout, idx) => { let LayoutElement = layout.component; diff --git a/react/src/layout/text.tsx b/react/src/layout/text.tsx index 994ae8a60c..c467696293 100644 --- a/react/src/layout/text.tsx +++ b/react/src/layout/text.tsx @@ -1,8 +1,8 @@ import React from "react"; import { FunctionComponent, useContext } from "react"; -import { Dependency } from "../data/dependency"; -import { CModelsWrapper } from "../data/wrapper"; -import { interpolate, ValueSelectors } from "../utility/string"; +import { StoreTypes } from "../data/data"; +import { CHandleFactory } from "../data/handle"; +import { interpolate } from "../utility/string"; import { Layout } from "./layout"; export type TextAlign = "left" | "right" | "center" @@ -16,9 +16,9 @@ export type TextConfig = { export class TextLayout extends Layout { component: FunctionComponent<{ [key: string]: any; }> = (props) => { - let modelsWrapper = useContext(CModelsWrapper); + let handleFactory = useContext(CHandleFactory); - let interpText = interpolate(this.config.text).withDependencies(modelsWrapper, ValueSelectors.Models).raw(); + let interpText = interpolate(this.config.text).withDependencies(handleFactory, StoreTypes.Models).raw(); let getTextElement = (type: TextType) => { switch(type) { case "header": diff --git a/react/src/store/common.ts b/react/src/store/common.ts index 365ba91125..82695cf851 100644 --- a/react/src/store/common.ts +++ b/react/src/store/common.ts @@ -38,7 +38,7 @@ export const makeSlice = (name: string): { name, initialState: {}, reducers: { - updateFormState: (state, {payload: {name, value}}: {payload: ModelStateUpdate}) => { + updateModel: (state, {payload: {name, value}}: {payload: ModelStateUpdate}) => { (state[name] as any) = value; } } diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 48ebcf5432..95281cc554 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -49,7 +49,7 @@ export class InterpolationBase { let valuesArr = mappingsArr.map(mapping => { return { ...mapping, - value: (valueSelector)(handleFactory.createHandle(mapping.dependency, type).hook().value) + value: (valueSelector)(handleFactory.createHandle(mapping.dependency, type).hook().value) } }) diff --git a/react/utility/convertschema.ts b/react/utility/convertschema.ts deleted file mode 100644 index 31776687a6..0000000000 --- a/react/utility/convertschema.ts +++ /dev/null @@ -1,426 +0,0 @@ -let fs = require("fs"); -let { Command } = require("commander"); - -class Dependency { - modelName: string; - fieldName: string; - - constructor(dependencyString: string) { - let { modelName, fieldName } = this.mapDependencyNameToParts(dependencyString); - this.modelName = modelName; - this.fieldName = fieldName; - } - - mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string } = (dep) => { - let [modelName, fieldName] = dep.split('.').filter((s: string) => s && s.length > 0); - return { - modelName, - fieldName - } - } - - getDependencyString: () => string = () => { - return this.modelName + "." + this.fieldName; - } -} - -function mapProperties(obj: {[key: string]: I}, mapFunc: (name: string, value: I) => O): {[key: string]: O} { - return Object.fromEntries( - Object.entries(obj).map(([propName, propValue]) => { - return [propName, mapFunc(propName, propValue)] - }) - ) -} - -type OldSchemaEnum = [ - value: string, - displayName: string -][] - -type SchemaLayoutJson = { - layout: string, - config: any -} - -type ScheamFieldJson = { - displayName: string, - type: string, - defaultValue?: T, - description?: string, - shown?: string, - min?: number, - max?: number -} - -type SchemaModelJson = { - [fieldName: string]: ScheamFieldJson -} - -type SchemaModelsJson = {[modelName: string]: SchemaModelJson}; - -type SchemaTypeJson = { - base: string, - config: {[key: string]: any} -} - -type SchemaRoutesJson = { - [key: string]: string -} - -type SchemaJson = { - constants: {[key: string]: any}, - type: {[typeName: string]: SchemaTypeJson}, - model: SchemaModelsJson, - view: SchemaLayoutJson[], - route: SchemaRoutesJson, - reactRoute: SchemaRoutesJson -} - -type OldSchemaModel = { - [fieldName: string]: [ - displayName: string, - typeName: string, - defaultValue: any, - description?: string, - min?: number, - max?: number - ] -} - -type OldSchemaModels = {[modelName: string]: OldSchemaModel}; -type OldSchemaView = {[key: string]: any}; -type OldSchemaViews = {[viewName: string]: OldSchemaView}; - -type OldSchema = { - enum: {[enumName: string]: OldSchemaEnum}, - model: OldSchemaModels - view: OldSchemaViews -} - - - -function readSchema(fileName: string): OldSchema { - let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); - let fileJson = JSON.parse(fileString) as OldSchema; - return fileJson; -} - -function mergeObjects(child: {[key: string]: any}, parents: {[key: string]: any}[]): {[key: string]: any} { - let no = {}; - (parents || []).forEach(o => Object.assign(no, o)); - Object.assign(no, child); - return no; -} - -function mergeArrays(child: any[], parents: any[][]): any[] { - let na = []; - (parents || []).forEach(a => na.push(...a)); - na.push(...child); - return na; -} - -function performInheritances(objects: {[key: string]: T}, mergeFunc: (original: T, inh: T[]) => T): {[key: string]: T} { - return Object.fromEntries( - Object.entries(objects).map(([key, value]) => { - if(key.startsWith("_")) { - return undefined; - } - let sup: string[] = value["_super"]; - if(sup) { - value["_super"] = undefined; - let inh: T[] = sup.filter(v => v !== "model" && v !== "view" && v !== "_").map(n => objects[n]); - return [ - key, - mergeFunc(value, inh) - ] - } - return [ - key, - value - ] - }).filter(e => e !== undefined) - ) -} - -function modelInheritances(models: OldSchemaModels): OldSchemaModels { - return performInheritances(models, (o, i) => mergeObjects(o, i)); -} - -function viewInheritances(views: OldSchemaViews): OldSchemaViews { - return performInheritances(views, (o, i) => { - let mergeField = (fieldName: string) => { - o[fieldName] = o[fieldName] || []; - o[fieldName] = mergeArrays(o[fieldName], i.map(v => v[fieldName] || {})) - if(Object.keys(o[fieldName]).length == 0) { - o[fieldName] = undefined; - } - } - mergeField("basic"); - mergeField("advanced"); - return o; - }) -} - -function convertSchema(schema: OldSchema) { - let oModels = modelInheritances(schema.model); - //saveSchema("omodels.json", oModels); - let models = mapProperties(oModels, (modelName, model) => convertModel(model)); - let types = mapProperties(schema.enum, (enumName, e) => convertEnum(e)); - - let views = []; - let uViews = []; - - let oViews = viewInheritances(schema.view); - //saveSchema("oviews.json", oViews) - mapProperties(oViews, (viewName, view) => { - let [converted, cv] = convertView(viewName, view, models); - if(converted) { - views.push(cv); - } else { - uViews.push(cv); - } - }) - - return { - model: models, - type: types, - view: views, - unhandled: uViews - } -} - -function convertModel(model: OldSchemaModel): SchemaModelJson { - let newModel = {}; - for(let [fieldName, field] of Object.entries(model)) { - let [name, typeString, defaultValue, description, min, max] = field; - newModel[fieldName] = { - displayName: name, - type: typeString, - defaultValue, - description, - min, - max - } - } - return newModel; -} - -function convertEnum(old: OldSchemaEnum): SchemaTypeJson { - return { - base: "Enum", - config: { - allowedValues: old - } - } -} - -function convertView(viewName: string, view: {[key: string]: any}, models: SchemaModelsJson): [converted: boolean, view: {[key: string]: any}] { - let keys = Object.keys(view); - - let withMeta = (viewName, view) => { - view["_NAME"] = viewName; - return view; - } - - if(keys.includes("basic") || keys.includes("advanced")) { - // is panel - return [true, withMeta(viewName, convertPanel(viewName, view, models))] - } else { - return [false, withMeta(viewName, view)]; - } -} - -function fullFieldName(fieldName: string, modelName: string) { - let r = /\./ - if(r.test(fieldName)) { - return fieldName; - } - return `${modelName}.${fieldName}`; -} - - -function convertPanel( - viewName: string, - view: {[key: string]: any}, - models: SchemaModelsJson -): {[key: string]: any} { - let modelName = viewName; - if(view.model) { - modelName = view.model; - } - - let convertPanelContents = (children: any[]): SchemaLayoutJson[] => { - let tabs: [name: string, views: any[]][] = []; - let convertArrayChild = (ac: any) => { - /** - * ac could be either - * [string, ...] as a tab or - * [[string, ...], ...] as a table - */ - if(Array.isArray(ac[0])) { - // is table - return fieldTableLayout(ac, modelName, models); - } else { - tabs.push([ac[0], convertPanelContents(ac[1])]) - return undefined; - } - } - - let newChildren = []; - let fieldNames = []; - let popFields = () => { - if(fieldNames.length > 0) { - newChildren.push(fieldListLayout(fieldNames)); - fieldNames = []; - } - } - for(let child of children) { - if(typeof child === "string") { - fieldNames.push(fullFieldName(child, modelName)); - } else { - popFields(); - if(Array.isArray(child)) { - let c = convertArrayChild(child); - if(c !== undefined) { - newChildren.push(c); - } - } else { - throw new Error(`unknown child=${JSON.stringify(child)}`); - } - } - } - popFields(); - - if(tabs.length > 0) { - newChildren.push(tabsLayout(tabs)) - } - - return newChildren; - } - - let config: {[key: string]: any} = {}; - - if(view.basic) { - config['basic'] = convertPanelContents(view.basic); - } - - if(view.advanced) { - config['advanced'] = convertPanelContents(view.advanced); - } - - config['title'] = view.title; - - return { - layout: "panel", - config - } -} - -function layout( - type: string, - config: {[key: string]: any} -) { - return { - layout: type, - config - } -} - -function tabsLayout( - tabs: [name: string, views: any[]][], - -): SchemaLayoutJson { - let tab = (name: string, views: any[]) => { - return { - name, - items: views - } - } - - return layout( - "tabs", - { - tabs: tabs.map(([name, views]) => tab(name, views)) - } - ) -} - -function fieldListLayout(fieldNames: string[]) { - return layout("fieldList", { - fields: fieldNames - }) -} - -function fieldTableLayout( - columns: [name: string, fieldNames: string[]][], - modelName: string, - models: SchemaModelsJson -) { - let columnNames = columns.map(([name,]) => name); - let rows: { - label: string, - description: string, - fields: string[] - }[] = []; - let lens = [...new Set(columns.map(([, fields]) => fields.length))]; - if(lens.length > 1) { - //throw new Error(`unequal table columns=${JSON.stringify(columns)} field lengths=${lens}`) - // return these broken into columns manually instead of as a table - return layout("hStack", { - items: columns.map(([name, fieldNames]) => { - return layout("vStack", { - items: [ - layout("text", { - type: "header", - align: "left", - text: name - }), - fieldListLayout(fieldNames.map(fn => fullFieldName(fn, modelName))) - ] - }) - }) - }) - } - if(lens.length > 0) { - let len = lens[0]; - for(let i = 0; i < len; i++) { - let fields = columns.map(([, fields]) => fullFieldName(fields[i], modelName)); - let dep = new Dependency(fields[0]); - let firstModelField = models[dep.modelName][dep.fieldName] - rows.push({ - label: firstModelField.displayName, - description: firstModelField.description, - fields - }) - } - } - return layout( - "fieldTable", - { - columns: columnNames, - rows - } - ) -} - -function saveSchema(fileName: string, schema): void { - fs.writeFileSync(fileName, JSON.stringify(schema)); -} - -let program = new Command(); -program -.arguments("") -.option("-o, --output ", "output filename") -.action((inFile: string, options: {output?: string}) => { - let defaultOutfile = () => { - let sep =inFile.indexOf("."); - if(sep < 0) { - return inFile + "-conv"; - } - - return inFile.substring(0, sep) + "-conv" + inFile.substring(sep); - } - let outFile = options.output || defaultOutfile(); - saveSchema(outFile, convertSchema(readSchema(inFile))); -}) -program.parse(); From 1b721caf1d42558675419fdfe5eb57157cf291ee Mon Sep 17 00:00:00 2001 From: garsuga Date: Mon, 10 Apr 2023 22:10:31 +0000 Subject: [PATCH 25/68] undo accidental delete --- react/utility/convertschema.ts | 426 +++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 react/utility/convertschema.ts diff --git a/react/utility/convertschema.ts b/react/utility/convertschema.ts new file mode 100644 index 0000000000..31776687a6 --- /dev/null +++ b/react/utility/convertschema.ts @@ -0,0 +1,426 @@ +let fs = require("fs"); +let { Command } = require("commander"); + +class Dependency { + modelName: string; + fieldName: string; + + constructor(dependencyString: string) { + let { modelName, fieldName } = this.mapDependencyNameToParts(dependencyString); + this.modelName = modelName; + this.fieldName = fieldName; + } + + mapDependencyNameToParts: (dep: string) => { modelName: string, fieldName: string } = (dep) => { + let [modelName, fieldName] = dep.split('.').filter((s: string) => s && s.length > 0); + return { + modelName, + fieldName + } + } + + getDependencyString: () => string = () => { + return this.modelName + "." + this.fieldName; + } +} + +function mapProperties(obj: {[key: string]: I}, mapFunc: (name: string, value: I) => O): {[key: string]: O} { + return Object.fromEntries( + Object.entries(obj).map(([propName, propValue]) => { + return [propName, mapFunc(propName, propValue)] + }) + ) +} + +type OldSchemaEnum = [ + value: string, + displayName: string +][] + +type SchemaLayoutJson = { + layout: string, + config: any +} + +type ScheamFieldJson = { + displayName: string, + type: string, + defaultValue?: T, + description?: string, + shown?: string, + min?: number, + max?: number +} + +type SchemaModelJson = { + [fieldName: string]: ScheamFieldJson +} + +type SchemaModelsJson = {[modelName: string]: SchemaModelJson}; + +type SchemaTypeJson = { + base: string, + config: {[key: string]: any} +} + +type SchemaRoutesJson = { + [key: string]: string +} + +type SchemaJson = { + constants: {[key: string]: any}, + type: {[typeName: string]: SchemaTypeJson}, + model: SchemaModelsJson, + view: SchemaLayoutJson[], + route: SchemaRoutesJson, + reactRoute: SchemaRoutesJson +} + +type OldSchemaModel = { + [fieldName: string]: [ + displayName: string, + typeName: string, + defaultValue: any, + description?: string, + min?: number, + max?: number + ] +} + +type OldSchemaModels = {[modelName: string]: OldSchemaModel}; +type OldSchemaView = {[key: string]: any}; +type OldSchemaViews = {[viewName: string]: OldSchemaView}; + +type OldSchema = { + enum: {[enumName: string]: OldSchemaEnum}, + model: OldSchemaModels + view: OldSchemaViews +} + + + +function readSchema(fileName: string): OldSchema { + let fileString = fs.readFileSync(fileName, { encoding: "utf-8" }); + let fileJson = JSON.parse(fileString) as OldSchema; + return fileJson; +} + +function mergeObjects(child: {[key: string]: any}, parents: {[key: string]: any}[]): {[key: string]: any} { + let no = {}; + (parents || []).forEach(o => Object.assign(no, o)); + Object.assign(no, child); + return no; +} + +function mergeArrays(child: any[], parents: any[][]): any[] { + let na = []; + (parents || []).forEach(a => na.push(...a)); + na.push(...child); + return na; +} + +function performInheritances(objects: {[key: string]: T}, mergeFunc: (original: T, inh: T[]) => T): {[key: string]: T} { + return Object.fromEntries( + Object.entries(objects).map(([key, value]) => { + if(key.startsWith("_")) { + return undefined; + } + let sup: string[] = value["_super"]; + if(sup) { + value["_super"] = undefined; + let inh: T[] = sup.filter(v => v !== "model" && v !== "view" && v !== "_").map(n => objects[n]); + return [ + key, + mergeFunc(value, inh) + ] + } + return [ + key, + value + ] + }).filter(e => e !== undefined) + ) +} + +function modelInheritances(models: OldSchemaModels): OldSchemaModels { + return performInheritances(models, (o, i) => mergeObjects(o, i)); +} + +function viewInheritances(views: OldSchemaViews): OldSchemaViews { + return performInheritances(views, (o, i) => { + let mergeField = (fieldName: string) => { + o[fieldName] = o[fieldName] || []; + o[fieldName] = mergeArrays(o[fieldName], i.map(v => v[fieldName] || {})) + if(Object.keys(o[fieldName]).length == 0) { + o[fieldName] = undefined; + } + } + mergeField("basic"); + mergeField("advanced"); + return o; + }) +} + +function convertSchema(schema: OldSchema) { + let oModels = modelInheritances(schema.model); + //saveSchema("omodels.json", oModels); + let models = mapProperties(oModels, (modelName, model) => convertModel(model)); + let types = mapProperties(schema.enum, (enumName, e) => convertEnum(e)); + + let views = []; + let uViews = []; + + let oViews = viewInheritances(schema.view); + //saveSchema("oviews.json", oViews) + mapProperties(oViews, (viewName, view) => { + let [converted, cv] = convertView(viewName, view, models); + if(converted) { + views.push(cv); + } else { + uViews.push(cv); + } + }) + + return { + model: models, + type: types, + view: views, + unhandled: uViews + } +} + +function convertModel(model: OldSchemaModel): SchemaModelJson { + let newModel = {}; + for(let [fieldName, field] of Object.entries(model)) { + let [name, typeString, defaultValue, description, min, max] = field; + newModel[fieldName] = { + displayName: name, + type: typeString, + defaultValue, + description, + min, + max + } + } + return newModel; +} + +function convertEnum(old: OldSchemaEnum): SchemaTypeJson { + return { + base: "Enum", + config: { + allowedValues: old + } + } +} + +function convertView(viewName: string, view: {[key: string]: any}, models: SchemaModelsJson): [converted: boolean, view: {[key: string]: any}] { + let keys = Object.keys(view); + + let withMeta = (viewName, view) => { + view["_NAME"] = viewName; + return view; + } + + if(keys.includes("basic") || keys.includes("advanced")) { + // is panel + return [true, withMeta(viewName, convertPanel(viewName, view, models))] + } else { + return [false, withMeta(viewName, view)]; + } +} + +function fullFieldName(fieldName: string, modelName: string) { + let r = /\./ + if(r.test(fieldName)) { + return fieldName; + } + return `${modelName}.${fieldName}`; +} + + +function convertPanel( + viewName: string, + view: {[key: string]: any}, + models: SchemaModelsJson +): {[key: string]: any} { + let modelName = viewName; + if(view.model) { + modelName = view.model; + } + + let convertPanelContents = (children: any[]): SchemaLayoutJson[] => { + let tabs: [name: string, views: any[]][] = []; + let convertArrayChild = (ac: any) => { + /** + * ac could be either + * [string, ...] as a tab or + * [[string, ...], ...] as a table + */ + if(Array.isArray(ac[0])) { + // is table + return fieldTableLayout(ac, modelName, models); + } else { + tabs.push([ac[0], convertPanelContents(ac[1])]) + return undefined; + } + } + + let newChildren = []; + let fieldNames = []; + let popFields = () => { + if(fieldNames.length > 0) { + newChildren.push(fieldListLayout(fieldNames)); + fieldNames = []; + } + } + for(let child of children) { + if(typeof child === "string") { + fieldNames.push(fullFieldName(child, modelName)); + } else { + popFields(); + if(Array.isArray(child)) { + let c = convertArrayChild(child); + if(c !== undefined) { + newChildren.push(c); + } + } else { + throw new Error(`unknown child=${JSON.stringify(child)}`); + } + } + } + popFields(); + + if(tabs.length > 0) { + newChildren.push(tabsLayout(tabs)) + } + + return newChildren; + } + + let config: {[key: string]: any} = {}; + + if(view.basic) { + config['basic'] = convertPanelContents(view.basic); + } + + if(view.advanced) { + config['advanced'] = convertPanelContents(view.advanced); + } + + config['title'] = view.title; + + return { + layout: "panel", + config + } +} + +function layout( + type: string, + config: {[key: string]: any} +) { + return { + layout: type, + config + } +} + +function tabsLayout( + tabs: [name: string, views: any[]][], + +): SchemaLayoutJson { + let tab = (name: string, views: any[]) => { + return { + name, + items: views + } + } + + return layout( + "tabs", + { + tabs: tabs.map(([name, views]) => tab(name, views)) + } + ) +} + +function fieldListLayout(fieldNames: string[]) { + return layout("fieldList", { + fields: fieldNames + }) +} + +function fieldTableLayout( + columns: [name: string, fieldNames: string[]][], + modelName: string, + models: SchemaModelsJson +) { + let columnNames = columns.map(([name,]) => name); + let rows: { + label: string, + description: string, + fields: string[] + }[] = []; + let lens = [...new Set(columns.map(([, fields]) => fields.length))]; + if(lens.length > 1) { + //throw new Error(`unequal table columns=${JSON.stringify(columns)} field lengths=${lens}`) + // return these broken into columns manually instead of as a table + return layout("hStack", { + items: columns.map(([name, fieldNames]) => { + return layout("vStack", { + items: [ + layout("text", { + type: "header", + align: "left", + text: name + }), + fieldListLayout(fieldNames.map(fn => fullFieldName(fn, modelName))) + ] + }) + }) + }) + } + if(lens.length > 0) { + let len = lens[0]; + for(let i = 0; i < len; i++) { + let fields = columns.map(([, fields]) => fullFieldName(fields[i], modelName)); + let dep = new Dependency(fields[0]); + let firstModelField = models[dep.modelName][dep.fieldName] + rows.push({ + label: firstModelField.displayName, + description: firstModelField.description, + fields + }) + } + } + return layout( + "fieldTable", + { + columns: columnNames, + rows + } + ) +} + +function saveSchema(fileName: string, schema): void { + fs.writeFileSync(fileName, JSON.stringify(schema)); +} + +let program = new Command(); +program +.arguments("") +.option("-o, --output ", "output filename") +.action((inFile: string, options: {output?: string}) => { + let defaultOutfile = () => { + let sep =inFile.indexOf("."); + if(sep < 0) { + return inFile + "-conv"; + } + + return inFile.substring(0, sep) + "-conv" + inFile.substring(sep); + } + let outFile = options.output || defaultOutfile(); + saveSchema(outFile, convertSchema(readSchema(inFile))); +}) +program.parse(); From a036b7ff785d9e63cb1e3b23d03b996cd592f6a4 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 13 Apr 2023 00:33:09 +0000 Subject: [PATCH 26/68] wip complete new data work and continue working on shadow beamline component --- react/package-lock.json | 1 + react/package.json | 1 + react/src/component/reusable/form.tsx | 17 ++- react/src/component/simulation.tsx | 32 ++--- react/src/data/alias.ts | 18 ++- react/src/data/data.ts | 28 +++++ react/src/data/form.ts | 112 ++++++++++++------ react/src/data/handle.ts | 58 ++++----- react/src/layout/beamline.tsx | 54 +++++---- react/src/layout/form.tsx | 11 +- react/src/layout/panel.tsx | 4 +- react/src/layout/report.tsx | 3 +- .../shadow/beamlineWatchpointReports.tsx | 68 +++++++---- react/src/store/common.ts | 5 +- react/src/store/formState.ts | 8 -- react/src/utility/object.ts | 37 ++++++ react/src/utility/string.ts | 7 ++ 17 files changed, 309 insertions(+), 155 deletions(-) diff --git a/react/package-lock.json b/react/package-lock.json index 49a307b647..80484b621f 100644 --- a/react/package-lock.json +++ b/react/package-lock.json @@ -24,6 +24,7 @@ "bootstrap": "^5.1.3", "bootstrap-icons": "^1.8.3", "html2canvas": "^1.4.1", + "lodash": "^4.17.21", "react": "^18.2.0", "react-bootstrap": "^2.4.0", "react-bootstrap-icons": "^1.8.4", diff --git a/react/package.json b/react/package.json index e3a58e45fc..567f4bac3a 100644 --- a/react/package.json +++ b/react/package.json @@ -19,6 +19,7 @@ "bootstrap": "^5.1.3", "bootstrap-icons": "^1.8.3", "html2canvas": "^1.4.1", + "lodash": "^4.17.21", "react": "^18.2.0", "react-bootstrap": "^2.4.0", "react-bootstrap-icons": "^1.8.4", diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 46339edc35..6a0e090602 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -10,15 +10,15 @@ import React, { useEffect } from "react"; import { - formStatesSlice, - initialFormStateFromValue + formActions, + formStatesSlice } from "../../store/formState"; import { useDispatch, useStore } from "react-redux"; import { AppWrapper, CSchema } from "../../data/appwrapper"; import { SimulationInfo } from "../simulation"; import { AnyAction, Dispatch, Store } from "redux"; -import { FormStateHandleFactory } from "../../data/form"; -import { modelActions, modelsSlice } from "../../store/models"; +import { FormStateHandleFactory, initialFormStateFromValue } from "../../data/form"; +import { modelsSlice } from "../../store/models"; import { mapProperties } from "../../utility/object"; export function FormField(props) { @@ -80,11 +80,9 @@ export function FormStateInitializer(props) { let dispatch = useDispatch(); let ms = store.getState()[modelsSlice.name] - let fs = store.getState()[formStatesSlice.name]; let modelNames = Object.keys(ms); useEffect(() => { - let state = store.getState(); modelNames.map(mn => { return { modelName: mn, @@ -98,13 +96,14 @@ export function FormStateInitializer(props) { if(!modelSchema) { throw new Error(`could not get schema for model=${modelName}`); } - dispatch(modelActions.updateModel({ + dispatch(formActions.updateModel({ name: modelName, - value: mapProperties(ms, ([_, fv]) => initialFormStateFromValue(fv)) + value: mapProperties(value, (_, fv) => initialFormStateFromValue(fv)) })); }); + console.log("formState", store.getState()[formStatesSlice.name]); updateHasInit(true); - }, []) + }) return hasInit && ( <>{props.children} diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 3102839b7c..96b0150c71 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -28,7 +28,7 @@ import * as Icon from "@fortawesome/free-solid-svg-icons"; import { useSetup } from "../hook/setup"; import { Portal } from "./reusable/portal"; import { downloadAs, getAttachmentFileName } from "../utility/download"; -import { Provider, useDispatch } from "react-redux"; +import { Provider, useDispatch, useStore } from "react-redux"; import { StoreState } from "../store/common"; import { configureStore } from "@reduxjs/toolkit"; import { formStatesSlice } from "../store/formState"; @@ -46,12 +46,12 @@ export type SimulationInfo = SimulationInfoRaw & { } function SimulationStoreInitializer(props: {[key: string]: any}) { - const modelsStore = configureStore({ // TODO: this belongs on the simulation root component + const [modelsStore, _] = useState(() => configureStore({ reducer: { [modelsSlice.name]: modelsSlice.reducer, [formStatesSlice.name]: formStatesSlice.reducer, }, - }); + })); return ( @@ -72,8 +72,6 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let routeHelper = useContext(CRouteHelper); let dispatch = useDispatch(); - console.log("modelActions", modelActions); - useEffect(() => { updateSimulationInfoPromise(new Promise((resolve, reject) => { fetch(routeHelper.globalRoute("simulationData", { @@ -97,8 +95,10 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri })) }, []) + let [handleFactory, _] = useState(new BaseHandleFactory(schema)) + return hasInit && simulationInfoPromise && ( - + {props.children} @@ -266,6 +266,8 @@ export function SimulationOuter(props) { let currentRelativeRouter = new RelativeRouteHelper(pathPrefix); let handleFactory = useContext(CHandleFactory); + let store = useStore(); + console.log("models", store.getState()[StoreTypes.Models.name]); let simNameHandle = handleFactory.createHandle(new Dependency("simulation.name"), StoreTypes.Models).hook(); useEffect(() => { @@ -300,18 +302,20 @@ export function SimulationRoot(props: {simulationId: string}) { // TODO: use multiple rows return ( - - - - + + + + + {layoutComponents} - - - - + + + + + ) } diff --git a/react/src/data/alias.ts b/react/src/data/alias.ts index 8326f25b55..2313eef058 100644 --- a/react/src/data/alias.ts +++ b/react/src/data/alias.ts @@ -4,6 +4,7 @@ import { Schema } from "../utility/schema"; import { getValueSelector, StoreType } from "./data"; import { Dependency } from "./dependency"; import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; +import cloneDeep from 'lodash/cloneDeep'; export type ArrayAliases = { realDataLocation: { @@ -16,23 +17,28 @@ export type ArrayAliases = { }[] export class HandleFactoryWithArrayAliases extends HandleFactory { - constructor(schema: Schema, private aliases: ArrayAliases, private parent: HandleFactory) { - super(schema); + constructor(schema: Schema, private aliases: ArrayAliases, public parent: HandleFactory) { + super(schema, parent); } createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle> { + console.log("creating aliased handle"); let alias = this.aliases.find(a => a.fake === dependency.modelName); + console.log("alias", alias); if(alias !== undefined) { let edh = this.parent.createHandle(new Dependency(`${alias.realDataLocation.modelName}.${alias.realDataLocation.fieldName}`), type); return new (class implements EmptyDataHandle { private createDummyHandle(dh: DataHandle): DataHandle { let mv = getValueSelector(type)(dh.value)[alias.realDataLocation.index]; - let fv = mv[dependency.fieldName]; + console.log("array element value", mv); + let fv = mv.item[dependency.fieldName]; + console.log("array element field value", fv); return new (class extends DataHandle { write(value: F, state: StoreState, dispatch: Dispatch) { - let av = getValueSelector(type)(dh.value) as ArrayFieldState; - av[alias.realDataLocation.index][dependency.fieldName] = value; - dh.write(dh.value, state, dispatch); + let v = cloneDeep(dh.value); + let av = getValueSelector(type)(v) as ArrayFieldState; + av[alias.realDataLocation.index].item[dependency.fieldName] = value; + dh.write(v, state, dispatch); } })(fv); } diff --git a/react/src/data/data.ts b/react/src/data/data.ts index 69391f3d88..3f4f363458 100644 --- a/react/src/data/data.ts +++ b/react/src/data/data.ts @@ -2,6 +2,7 @@ import { ModelSelector, ModelWriteActionCreator } from "../store/common"; import { formActions, FormFieldState, FormModelState, formSelectors, formStatesSlice } from "../store/formState"; import { modelActions, modelSelectors, modelsSlice, ModelState } from "../store/models"; import { SchemaModel } from "../utility/schema"; +import { mapProperties } from "../utility/object"; export class StoreType { constructor(public name: string) {} @@ -41,3 +42,30 @@ export function newModelFromSchema(modelSchema: SchemaModel, overrides: {[key: s let defaults = Object.fromEntries(Object.entries(modelSchema).filter(([name, value]) => value.defaultValue !== undefined).map(([name, value]) => [name, value.defaultValue])) return Object.assign(defaults, overrides); } + +export function expandDataStructure(value: T, expansionFn: (v: T) => R): R { + if(Array.isArray(value)) { + return expansionFn( + (value as any[]).map(ele => { + return { + model: ele.model, + item: mapProperties(ele.item, (_, v) => expansionFn(v as T)) + } + }) as T + ) + } + return expansionFn(value); +} + +export function revertDataStructure(value: T, revertFn: (v: T) => R): R { + let v = revertFn(value); + if(Array.isArray(v)) { + return (v as any[]).map(ele => { + return { + model: ele.model, + item: mapProperties(ele.item, (_, x) => revertFn(x as T)) + } + }) as R + } + return v; +} diff --git a/react/src/data/form.ts b/react/src/data/form.ts index f681d0dfe1..dd745994c0 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -1,19 +1,18 @@ import { useState } from "react"; -import { Dispatch, AnyAction, Store } from "redux"; +import { Dispatch, AnyAction } from "redux"; import { StoreState } from "../store/common"; -import { FormModelState, initialFormStateFromValue } from "../store/formState"; +import { FormFieldState, FormModelState } from "../store/formState"; import { ModelState } from "../store/models"; -import { mapProperties } from "../utility/object"; +import { Dictionary, mapProperties } from "../utility/object"; import { Schema } from "../utility/schema"; -import { StoreType, StoreTypes } from "./data"; +import { StoreType, StoreTypes, expandDataStructure, revertDataStructure, getValueSelector } from "./data"; import { Dependency } from "./dependency"; -import { BaseHandleFactory, DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; +import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; type FormActionFunc = (state: any, dispatch: Dispatch) => void type FormSelectorFunc = (state: any) => V -type FormActionsKeyPair = { - key: any, +type FormActions = { save: FormActionFunc, cancel: FormActionFunc, valid: FormSelectorFunc @@ -23,15 +22,27 @@ export function formStateFromModelState(modelState: ModelState): FormModelState return mapProperties(modelState, (name, value) => initialFormStateFromValue(value)); } +function formStateFromSingleValue(value: T): FormFieldState { + return { + valid: true, + value, + touched: false + } +} + +export function initialFormStateFromValue(value: T): FormFieldState { + return expandDataStructure(value, formStateFromSingleValue); +} + export class FormStateHandleFactory extends HandleFactory { - private updated: FormActionsKeyPair[] = [] - private listeners: (() => void)[] = []; + private updated: Dictionary = new Dictionary(); + private listeners: Dictionary void> = new Dictionary(); - constructor(schema: Schema, private parent: HandleFactory) { - super(schema); + constructor(schema: Schema, public parent: HandleFactory) { + super(schema, parent); } - private emptyDataHandleFor(parent: EmptyDataHandle, updateCallback: (dh: DataHandle) => void): EmptyDataHandle { + private emptyDataHandleFor = (parent: EmptyDataHandle, updateCallback: (dh: DataHandle) => void): EmptyDataHandle => { return new (class implements EmptyDataHandle { private dataHandleFor(parent: DataHandle): DataHandle { let dh: DataHandle = new (class extends DataHandle { @@ -53,57 +64,84 @@ export class FormStateHandleFactory extends HandleFactory { })(); } - private addToUpdated = (kp: FormActionsKeyPair) => { - let idx = this.updated.findIndex(u => u.key === kp.key); - if(idx >= 0) { - this.updated.splice(idx, 1); - } - this.updated.push(kp) + private addToUpdated = (key: any, value: FormActions) => { + console.log("add to updated"); + this.updated.put(key, value); + console.log("updated", this.updated); + this.notifyListeners(); + } + + private notifyListeners = () => { + this.listeners.items().forEach(l => l.value()); } - private notifyListeners() { - this.listeners.forEach(l => l()); + private callParentFunctions = (fnName: 'save' | 'cancel', state: any, dispatch: Dispatch) => { + console.log(`${fnName} ------------>`) + let p = this.parent; + while(p) { + let fn: FormActionFunc = p[fnName]; + if(fn) { + fn(state, dispatch); + } + p = p.parent; + } + console.log(`${fnName} <-------------`) } - save(state: any, dispatch: Dispatch) { - this.updated.forEach(u => u.save(state, dispatch)); - this.updated = []; + save: FormActionFunc = (state: any, dispatch: Dispatch) => { + console.log("SAVE CALLED"); + this.updated.items().forEach(u => u.value.save(state, dispatch)); + this.updated = new Dictionary(); this.notifyListeners(); + this.callParentFunctions("save", state, dispatch); } - cancel(state: any, dispatch: Dispatch) { - this.updated.forEach(u => u.cancel(state, dispatch)); - this.updated = []; + cancel: FormActionFunc = (state: any, dispatch: Dispatch) => { + console.log("CANCEL CALLED"); + this.updated.items().forEach(u => u.value.cancel(state, dispatch)); + this.updated = new Dictionary(); this.notifyListeners(); + this.callParentFunctions("cancel", state, dispatch); } - isDirty(): boolean { - return this.updated.length > 0; + isDirty = (): boolean => { + console.log("IS DIRTY CALLED", this.updated); + //debugger; + return this.updated.items().length > 0; } - isValid(state: any): boolean { - return !this.updated.map(u => !!u.valid(state)).includes(false); + isValid = (state: any): boolean => { + return !this.updated.items().map(u => !!u.value.valid(state)).includes(false); } - useUpdates() { + useUpdates = (key: any) => { let [v, u] = useState({}); - this.listeners.push(() => u({})); + this.listeners.put(key, () => u({})); } - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { + createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle => { let edh = this.parent.createHandle(dependency, type); if(type === StoreTypes.FormState) { return this.emptyDataHandleFor(edh, (dh: DataHandle) => { let f = (state: any) => this.parent.createHandle(dependency, StoreTypes.FormState).initialize(state); let m = (state: any) => this.parent.createHandle(dependency, StoreTypes.Models).initialize(state); - this.addToUpdated({ - key: dh, + this.addToUpdated(dh, + { save: (state: StoreState, dispatch: Dispatch) => { - let v = this.schema.models[dependency.modelName][dependency.fieldName].type.toModelValue(f(state).value); + console.log(`SAVING ${dependency.getDependencyString()}`); + /*if(dependency.getDependencyString() === "beamline.elements") { + debugger; + }*/ + let type = this.schema.models[dependency.modelName][dependency.fieldName].type + console.log("type", type); + let rawValue = revertDataStructure(f(state).value, getValueSelector(StoreTypes.FormState)); + console.log("rawValue", rawValue); + let v = type.toModelValue(rawValue); + console.log("value", v); m(state).write(v, state, dispatch); }, cancel: (state: StoreState, dispatch: Dispatch) => { - f(state).write(initialFormStateFromValue(m(state).value), state, dispatch); + //f(state).write(initialFormStateFromValue(m(state).value), state, dispatch); }, valid: (state: any): boolean => { return f(state).value.valid; diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 3c87e1898b..6f947ac68f 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -1,10 +1,9 @@ import React from "react"; -import { useSelector, useStore } from "react-redux"; +import { useSelector } from "react-redux"; import { AnyAction, Dispatch } from "redux"; -import { StoreState } from "../store/common"; -import { ModelState } from "../store/models"; import { Schema } from "../utility/schema"; -import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, StoreType, StoreTypes } from "./data"; +import { hashCode } from "../utility/string"; +import { getModelReadSelector, getModelWriteActionCreator, getValueSelector, revertDataStructure, StoreType } from "./data"; import { Dependency } from "./dependency"; export const CHandleFactory = React.createContext(undefined); @@ -14,7 +13,7 @@ export abstract class DataHandle { this.value = currentValue; } - abstract write(value: F, state: StoreState, dispatch: Dispatch); + abstract write(value: F, state: any, dispatch: Dispatch); readonly value: F; } @@ -33,9 +32,8 @@ export interface EmptyDataHandle = DataHandle(selector: (state: any) => M) => M; export abstract class HandleFactory { - constructor(protected schema: Schema) {} + constructor(protected schema: Schema, public parent?: HandleFactory) {} abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; - //abstract createArrayHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; } export class BaseHandleFactory extends HandleFactory { @@ -44,7 +42,7 @@ export class BaseHandleFactory extends HandleFactory { let mac = getModelWriteActionCreator(type); let cdh = (value: F): DataHandle => { return new (class extends DataHandle { - write = (value: F, state: StoreState, dispatch: Dispatch) => { + write = (value: F, state: any, dispatch: Dispatch) => { let mv = {...state[type.name][dependency.modelName]}; mv[dependency.fieldName] = value; dispatch(mac(dependency.modelName, mv)); @@ -56,7 +54,9 @@ export class BaseHandleFactory extends HandleFactory { return cdh(ms(state)[dependency.fieldName]); }, hook: () => { - return cdh(useSelector(ms)[dependency.fieldName]); + let mv = useSelector(ms); + //console.log("dependency", dependency.getDependencyString(), mv); + return cdh(mv[dependency.fieldName]); } } } @@ -77,43 +77,37 @@ export class DependencyReader { private expandWildcard(dependency: Dependency): Dependency[] { if(dependency.fieldName === `*`) { - return Object.keys(this.schema.models[dependency.fieldName]).map(fName => new Dependency(`${dependency.modelName}.${fName}`)); + return Object.keys(this.schema.models[dependency.modelName]).map(fName => new Dependency(`${dependency.modelName}.${fName}`)); } return [dependency]; } - hook = (): DependencyValuePair[] => { - let vs = getValueSelector(this.type); - let newDeps = this.dependencies.flatMap(d => this.expandWildcard(d)); - - return newDeps.map(d => { - let c = (d: Dependency) => { - let ms = getModelReadSelector(this.type)(d.modelName); - return useSelector(ms)[d.fieldName]; - } - - return { - value: vs(c(d)), - dependency: d - } - }) + private hashify = (x: T): T | number => { + if(typeof(x) == "object") { + return hashCode(JSON.stringify(x)); + } + return x; } - initialize = (state: any): DependencyValuePair[] => { + getData = (su: SelectorUser): F[] => { let vs = getValueSelector(this.type); let newDeps = this.dependencies.flatMap(d => this.expandWildcard(d)); - return newDeps.map(d => { let c = (d: Dependency) => { let ms = getModelReadSelector(this.type)(d.modelName); - return ms(state)[d.fieldName]; + return su(ms)[d.fieldName]; } - return { - value: vs(c(d)), - dependency: d - } + return this.hashify(revertDataStructure(c(d), vs)); }) + } + + hook = (): F[] => { + return this.getData(s => useSelector(s)); + } + + initialize = (state: any): F[] => { + return this.getData(s => s(state)); } } diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 46473fe07f..2f4a88d4af 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -40,29 +40,42 @@ export function BeamlineThumbnail(props: { name: string, iconSrc: string, onClic ) } -export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: Layout[] }, onClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { - let { baseElement, onClick, modalShown, onHideModal } = props; +export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: Layout[] }, aliases: ArrayAliases, onClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { + let { baseElement, aliases, onClick, modalShown, onHideModal } = props; let routeHelper = useContext(CRouteHelper); let store = useStore(); let simulationInfoPromise = useContext(CSimulationInfoPromise); - let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + let schema = useContext(CSchema); + let handleFactory = useContext(CHandleFactory); + let [aliasedHandleFactory, _] = useState(new FormStateHandleFactory(schema, new HandleFactoryWithArrayAliases(schema, aliases, handleFactory))); + //aliasedHandleFactory.useUpdates(BeamlineItem); let dispatch = useDispatch(); let appWrapper = useContext(CAppWrapper); - let { submit: _submit, cancel: _cancel } = formActionFunctions({ - formHandleFactory, + let actionFunctions = formActionFunctions({ + formHandleFactory: aliasedHandleFactory, store, simulationInfoPromise, appWrapper, dispatch }); - let isDirty = formHandleFactory.isDirty(); - let isValid = formHandleFactory.isValid(store.getState()); + let _submit = () => { + actionFunctions.submit(); + onHideModal(); + } + + let _cancel = () => { + actionFunctions.cancel(); + onHideModal(); + } + + let isDirty = aliasedHandleFactory.isDirty(); + let isValid = aliasedHandleFactory.isValid(store.getState()); let actionButtons = return ( - <> +
@@ -83,7 +96,7 @@ export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: {isDirty && actionButtons} - +
) } @@ -103,6 +116,7 @@ export class BeamlineLayout extends Layout { let schema = useContext(CSchema); let dispatch = useDispatch(); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + formHandleFactory.useUpdates(BeamlineLayout); let appWrapper = useContext(CAppWrapper); let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); @@ -111,17 +125,18 @@ export class BeamlineLayout extends Layout { let handle = formHandleFactory.createHandle>>(beamlineDependency, StoreTypes.FormState).hook(); // TODO: form or model? + console.log("beamline handle value", handle); + let addBeamlineElement = (element: BeamlineElement) => { console.log("AAA"); let ms = schema.models[element.model]; // TODO: use generic methods let l = handle.value.value.length; - let prev: FormModelState | undefined = l > 0 ? handle.value.value[l - 1].item : undefined - let nextPosition: string = prev ? `${parseFloat(prev.position.value) + 5}` : "0"; - let nextId: string = prev ? `${parseInt(prev.id.value) + 1}` : "1"; + let nextId = handle.value.value.reduce((prev, cur) => Math.max(prev, parseInt(cur.item.id.value) + 1), 1); + let nextPos = handle.value.value.reduce((prev, cur) => Math.max(prev, parseFloat(cur.item.position.value) + 5), 0); let mv = newModelFromSchema(ms, { - id: nextId, - position: nextPosition, + id: `${nextId}`, + position: `${nextPos}`, type: element.model }) @@ -135,7 +150,7 @@ export class BeamlineLayout extends Layout { ...handle.value, touched: true, value: bv - }, store.getState()[StoreTypes.FormState.name], dispatch); + }, store.getState(), dispatch); console.log("ADD ELEMENT"); } @@ -158,9 +173,11 @@ export class BeamlineLayout extends Layout { let beamlineComponents = handle.value.value.map((e, i) => { let model = e.model; let ele: FormModelState = e.item; + console.log("ele", ele); let id = ele.id.value; console.log("id", id); let baseElement = findBaseElementByModel(model); + let aliases: ArrayAliases = [ { realDataLocation: { @@ -172,12 +189,9 @@ export class BeamlineLayout extends Layout { fake: model } ]; - - let aliasedHandleFactory = new HandleFactoryWithArrayAliases(schema, aliases, formHandleFactory); + return ( - - updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> - + updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> ) }) diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index ebc6cef000..abe5e102d5 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -1,5 +1,5 @@ import { LayoutProps, LayoutType, Layout } from "./layout"; -import React, { useContext } from "react"; +import React, { useContext, useState } from "react"; import { Row, Col, @@ -15,11 +15,12 @@ import { CHandleFactory } from "../data/handle"; import { StoreTypes } from "../data/data"; export function FormControllerElement(props: {children?: React.ReactNode}) { + console.log("FORM CTRL RENDER"); let schema = useContext(CSchema); let handleFactory = useContext(CHandleFactory); - let formHandleFactory = new FormStateHandleFactory(schema, handleFactory); + let [formHandleFactory, _] = useState(new FormStateHandleFactory(schema, handleFactory)); // TODO: form controller might need to "subscribe to updates" during save - formHandleFactory.useUpdates(); + formHandleFactory.useUpdates(FormControllerElement); return ( @@ -106,7 +107,7 @@ export class FieldGridLayout extends Layout { valid: fieldType.validate(value), touched: true, value - }, store.getState()[StoreTypes.FormState.name], dispatch) + }, store.getState(), dispatch) }} dependency={fieldDependency} inputComponent={fieldType.component}/> @@ -158,7 +159,7 @@ export class FieldListLayout extends Layout { valid: fieldType.validate(value), touched: true, value - }, store.getState()[StoreTypes.FormState.name], dispatch) + }, store.getState(), dispatch) }} inputComponent={fieldSchema.type.component}/> } diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 17cd6ee432..ca245e1af3 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -32,8 +32,10 @@ export class PanelLayout extends Layout { } component = (props: LayoutProps<{}>) => { + console.log("PANEL RENDER"); let simulationInfoPromise = useContext(CSimulationInfoPromise); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + formHandleFactory.useUpdates(PanelLayout); let appWrapper = useContext(CAppWrapper); let shown = useShown(this.config.shown, true, StoreTypes.Models); @@ -61,7 +63,7 @@ export class PanelLayout extends Layout { let formProps = { submit: submit, - cancel: formHandleFactory.cancel(store.getState(), dispatch), + cancel: () => formHandleFactory.cancel(store.getState(), dispatch), showButtons: formHandleFactory.isDirty(), formValid: formHandleFactory.isValid(store.getState()), mainChildren, diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index 0eeddcb658..0dc1a8d14b 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -50,7 +50,6 @@ export class AutoRunReportLayout extends Layout { let appName = useContext(CAppName); let schema = useContext(CSchema); let routeHelper = useContext(CRouteHelper); - let handleFactory = useContext(CHandleFactory); let reportDependencies = dependencies.map(dependencyString => new Dependency(dependencyString)); let dependentValues = new DependencyReader(reportDependencies, StoreTypes.Models, schema).hook(); @@ -60,6 +59,8 @@ export class AutoRunReportLayout extends Layout { let [model, updateModel] = useState(undefined); useEffect(() => { + console.log("EFFECT"); + console.log("dependent values", dependentValues); updateSimulationData(undefined); simulationInfoPromise.then(({ models, simulationId }) => { updateModel(models[report]); diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index e66f4ee605..3f7ca3dbfe 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -1,12 +1,14 @@ -import React from "react"; -import { FunctionComponent, useContext } from "react"; +import React, { RefObject, useRef } from "react"; +import { FunctionComponent, useContext, useState } from "react"; import { ArrayAliases, HandleFactoryWithArrayAliases } from "../../data/alias"; import { CSchema } from "../../data/appwrapper"; import { StoreTypes } from "../../data/data"; import { Dependency } from "../../data/dependency"; +import { FormStateHandleFactory } from "../../data/form"; import { CHandleFactory } from "../../data/handle"; import { ArrayFieldState } from "../../store/common"; import { ModelState } from "../../store/models"; +import { Dictionary } from "../../utility/object"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; @@ -15,6 +17,20 @@ export type BeamlineWatchpointReportsConfig = { watchpointReportsDependency: string } +function BeamlineWatchpointItem(props: {child: Layout, aliases: ArrayAliases} & {[key: string]: any}) { + let { aliases, child } = props; + let handleFactory = useContext(CHandleFactory); + let schema = useContext(CSchema); + let [aliasedHandleFactory, _] = useState(new FormStateHandleFactory(schema, new HandleFactoryWithArrayAliases(schema, aliases, handleFactory))); + aliasedHandleFactory.useUpdates(BeamlineWatchpointItem) + let Comp = child.component; + return ( + + + + ) +} + export class BeamlineWatchpointReports extends Layout { component: FunctionComponent<{ [key: string]: any; }> = (props) => { let watchpointReportsDependency = new Dependency(this.config.watchpointReportsDependency); @@ -24,20 +40,25 @@ export class BeamlineWatchpointReports extends Layout; let elementsValue = elementsHandle.value as ArrayFieldState; - let schema = useContext(CSchema); - let findElementById = (id: any) => elementsValue.find(e => e.item.id == id); + let findElementIndexById = (id: any) => elementsValue.findIndex(e => e.item.id == id); + let findElementById = (id: any) => elementsValue[findElementIndexById(id)] + + + let reportLayoutsRef: RefObject> = useRef(new Dictionary()); - let reportElements = reportsValue.map((report, index) => { - let id = report.item.id; + reportsValue.forEach((report, index) => { + let id = `${report.item.id}`; let ele = findElementById(id); - let position = ele.item.position; - let cfg = createPanelConfig(`watchpointReport${index}`, `Intensity Report, ${position}`); - return { - id: id, - layout: LAYOUTS.getLayoutForSchema(cfg) + if(!reportLayoutsRef.current.contains(id)) { + let cfg = createPanelConfig(`watchpointReport${index}`, new Dependency("beamlineElement.position")); + reportLayoutsRef.current.put(id, LAYOUTS.getLayoutForSchema(cfg)); } - }).map((e, index) => { + }) + + let reportElements = reportLayoutsRef.current.items().map((e, index) => { + let beamlineIndex = findElementIndexById(e.key); + let beamlineElement = findElementById(e.key); let aliases: ArrayAliases = [ { realDataLocation: { @@ -47,15 +68,22 @@ export class BeamlineWatchpointReports extends Layout - - - + + ) }) @@ -66,11 +94,11 @@ export class BeamlineWatchpointReports extends Layout = { [key: string]: M } -export const makeSlice = (name: string): { +export const makeSlice = (sliceName: string): { slice: Slice>, actions: StoreActions, selectors: StoreSelectors } => { let slice: Slice> = createSlice({ - name, + name: sliceName, initialState: {}, reducers: { updateModel: (state, {payload: {name, value}}: {payload: ModelStateUpdate}) => { + console.log(`UPDATE MODEL ${name} IN ${sliceName}`); (state[name] as any) = value; } } diff --git a/react/src/store/formState.ts b/react/src/store/formState.ts index e677e79a32..34f75fb056 100644 --- a/react/src/store/formState.ts +++ b/react/src/store/formState.ts @@ -6,14 +6,6 @@ export type FormFieldState = { touched: boolean } -export function initialFormStateFromValue(value: T): FormFieldState { - return { - valid: true, - value, - touched: false - } -} - export type FormModelState = { [fieldName: string]: FormFieldState } diff --git a/react/src/utility/object.ts b/react/src/utility/object.ts index 88c8b25f17..96c817dd8a 100644 --- a/react/src/utility/object.ts +++ b/react/src/utility/object.ts @@ -5,3 +5,40 @@ export function mapProperties(obj: {[key: string]: I}, mapFunc: (name: str }) ) } + +export type KeyValuePair = { + key: K, + value: V +} + +export class Dictionary { + constructor(initialRecords?: KeyValuePair[]) { + this.records = [...(initialRecords || [])]; + } + + private comparator = (searchKey: K) => (element: KeyValuePair) => element.key === searchKey + private records: KeyValuePair[] = []; + + get = (key: K): V => { + return this.records.find(this.comparator(key))?.value; + } + + contains = (key: K): boolean => { + return this.records.find(this.comparator(key)) !== undefined; + } + + items = (): KeyValuePair[] => { + return this.records; + } + + put = (key: K, value: V): void => { + let idx = this.records.findIndex(this.comparator(key)); + if(idx >= 0) { + this.records.splice(idx, 1); + } + this.records.push({ + key, + value + }) + } +} diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index 95281cc554..aaee74cee9 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -90,3 +90,10 @@ export function titleCaseString(str: string): string { return word.substring(0,1).toUpperCase() + (word.length > 1 ? word.substring(1) : ""); }).join(" "); } + +export function hashCode(s: string): number { + return s.split("").reduce(function(a, b) { + a = ((a << 5) - a) + b.charCodeAt(0); + return a & a; + }, 0); + } From 6fef81291f0e3c3d918cd44e6d140d548d0733ce Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 20 Apr 2023 21:01:12 +0000 Subject: [PATCH 27/68] complete shadow basic functionality --- react/src/component/simulation.tsx | 96 ++++++++++++- react/src/data/alias.ts | 49 ++++++- react/src/data/form.ts | 8 +- react/src/data/handle.ts | 2 +- react/src/hook/coupling.ts | 17 +++ react/src/layout/arrange/waterfall.tsx | 127 ++++++------------ react/src/layout/beamline.scss | 10 ++ react/src/layout/beamline.tsx | 56 +++++--- react/src/layout/form.tsx | 7 +- react/src/layout/panel.tsx | 1 - react/src/layout/report.tsx | 8 +- .../shadow/beamlineWatchpointReports.tsx | 78 +++++++---- react/src/store/common.ts | 1 - react/src/utility/object.ts | 14 +- react/src/utility/string.ts | 3 +- 15 files changed, 319 insertions(+), 158 deletions(-) create mode 100644 react/src/hook/coupling.ts create mode 100644 react/src/layout/beamline.scss diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 96b0150c71..788449168f 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -29,11 +29,12 @@ import { useSetup } from "../hook/setup"; import { Portal } from "./reusable/portal"; import { downloadAs, getAttachmentFileName } from "../utility/download"; import { Provider, useDispatch, useStore } from "react-redux"; -import { StoreState } from "../store/common"; -import { configureStore } from "@reduxjs/toolkit"; -import { formStatesSlice } from "../store/formState"; +import { ArrayFieldState, StoreState } from "../store/common"; +import { configureStore, Middleware } from "@reduxjs/toolkit"; +import { formActions, formSelectors, formStatesSlice } from "../store/formState"; import { BaseHandleFactory, CHandleFactory } from "../data/handle"; -import { StoreTypes } from "../data/data"; +import { getValueSelector, newModelFromSchema, StoreType, StoreTypes } from "../data/data"; +import { useCoupledState } from "../hook/coupling"; export type SimulationInfoRaw = { models: StoreState, @@ -46,11 +47,96 @@ export type SimulationInfo = SimulationInfoRaw & { } function SimulationStoreInitializer(props: {[key: string]: any}) { + let schema = useContext(CSchema); + + let shadowBeamlineWatchpointReportsMiddleware: Middleware = store => next => action => { + if(action.type === "models/updateModel") { + let { name, value } = action.payload; + if(name === "beamline") { + let watchpointReportsModel: ModelState = modelSelectors.selectModel("watchpointReports")(store.getState()); + if(watchpointReportsModel) { + let watchpointReports = watchpointReportsModel.reports as ArrayFieldState; + let bv: ArrayFieldState = value.elements; + let findWatchpointReportById = (id) => watchpointReports.find(e => e.item.id === id); + let reportsValue = bv.filter(e => e.model == "watch").map(e => { + let id = e.item.id; + let watchpointReport = findWatchpointReportById(id); // TODO: these ids need to be made more unique or errors will occur + if(!watchpointReport) { + watchpointReport = { + item: newModelFromSchema(schema.models["watchpointReport"], { id }), + model: "watchpointReport" + }; + } + + return { + report: watchpointReport, + position: e.item.position as number + } + }).sort((e1, e2) => e1.position - e2.position).map(e => e.report); + + store.dispatch(modelActions.updateModel({ name: "watchpointReports", value: { + reports: reportsValue + }})); + } + } + } + return next(action); + } + + let shadowBeamlineSortingMiddleware: Middleware = store => next => action => { + let sortValues = (v, vs) => v.sort((a, b) => { + return parseFloat(vs(a.item.position)) - parseFloat(vs(b.item.position)) + }); + + if(action.type === "models/updateModel") { + let { name, value } = action.payload; + if(name === "beamline") { + let vs = getValueSelector(StoreTypes.Models) + let v = vs(value.elements); + let nv = sortValues(v, vs); + + let formBeamlineModel: ModelState = formSelectors.selectModel("beamline")(store.getState()); + if(formBeamlineModel !== undefined) { + let fvs = getValueSelector(StoreTypes.FormState); + console.log("fbm", formBeamlineModel); + store.dispatch(formActions.updateModel({ + name, + value: { + ...formBeamlineModel, + elements: { + ...(formBeamlineModel.elements as any), + value: sortValues([...fvs(formBeamlineModel.elements as any)], fvs) + } + } + })) + } + + + return next(modelActions.updateModel({ + name, + value: { + ...value, + elements: nv + } + })); + } + } + + return next(action); + } + + // TODO make server saving middleware + + const [modelsStore, _] = useState(() => configureStore({ reducer: { [modelsSlice.name]: modelsSlice.reducer, [formStatesSlice.name]: formStatesSlice.reducer, }, + middleware: [ + shadowBeamlineWatchpointReportsMiddleware, + shadowBeamlineSortingMiddleware + ] })); return ( @@ -95,7 +181,7 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri })) }, []) - let [handleFactory, _] = useState(new BaseHandleFactory(schema)) + let [handleFactory, _] = useCoupledState(schema, new BaseHandleFactory(schema)) return hasInit && simulationInfoPromise && ( diff --git a/react/src/data/alias.ts b/react/src/data/alias.ts index 2313eef058..e44ea9f45e 100644 --- a/react/src/data/alias.ts +++ b/react/src/data/alias.ts @@ -5,6 +5,7 @@ import { getValueSelector, StoreType } from "./data"; import { Dependency } from "./dependency"; import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; import cloneDeep from 'lodash/cloneDeep'; +import { ModelState } from "../store/models"; export type ArrayAliases = { realDataLocation: { @@ -21,18 +22,18 @@ export class HandleFactoryWithArrayAliases extends HandleFactory { super(schema, parent); } - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle> { - console.log("creating aliased handle"); + createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle> => { let alias = this.aliases.find(a => a.fake === dependency.modelName); - console.log("alias", alias); if(alias !== undefined) { let edh = this.parent.createHandle(new Dependency(`${alias.realDataLocation.modelName}.${alias.realDataLocation.fieldName}`), type); return new (class implements EmptyDataHandle { private createDummyHandle(dh: DataHandle): DataHandle { let mv = getValueSelector(type)(dh.value)[alias.realDataLocation.index]; - console.log("array element value", mv); + if(!mv) { + console.error(`could not find index=${alias.realDataLocation.index}`); + console.error(`was looking in`, getValueSelector(type)(dh.value)) + } let fv = mv.item[dependency.fieldName]; - console.log("array element field value", fv); return new (class extends DataHandle { write(value: F, state: StoreState, dispatch: Dispatch) { let v = cloneDeep(dh.value); @@ -54,3 +55,41 @@ export class HandleFactoryWithArrayAliases extends HandleFactory { return this.parent.createHandle(dependency, type); } } + +export type HandleFactoryOverrides = { + fake: string, + value: ModelState +}[] + +export class HandleFactoryWithOverrides extends HandleFactory { + constructor(schema: Schema, private overrides: HandleFactoryOverrides, parent: HandleFactory) { + super(schema, parent); + } + + createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle> => { + let override = this.overrides.find(a => a.fake === dependency.modelName); + + if(override !== undefined) { + return new (class implements EmptyDataHandle { + private createDummyHandle(): DataHandle { + let mv = override.value; + let fv = mv[dependency.fieldName] as F; + return new (class extends DataHandle { + write() { + throw new Error("tried to write to read-only handle override"); + } + })(fv); + } + + initialize(state: any): DataHandle { + return this.createDummyHandle(); + } + hook(): DataHandle { + return this.createDummyHandle(); + } + })(); + } + + return this.parent.createHandle(dependency, type); + } +} diff --git a/react/src/data/form.ts b/react/src/data/form.ts index dd745994c0..3514544fc9 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -76,7 +76,6 @@ export class FormStateHandleFactory extends HandleFactory { } private callParentFunctions = (fnName: 'save' | 'cancel', state: any, dispatch: Dispatch) => { - console.log(`${fnName} ------------>`) let p = this.parent; while(p) { let fn: FormActionFunc = p[fnName]; @@ -85,11 +84,9 @@ export class FormStateHandleFactory extends HandleFactory { } p = p.parent; } - console.log(`${fnName} <-------------`) } save: FormActionFunc = (state: any, dispatch: Dispatch) => { - console.log("SAVE CALLED"); this.updated.items().forEach(u => u.value.save(state, dispatch)); this.updated = new Dictionary(); this.notifyListeners(); @@ -97,7 +94,6 @@ export class FormStateHandleFactory extends HandleFactory { } cancel: FormActionFunc = (state: any, dispatch: Dispatch) => { - console.log("CANCEL CALLED"); this.updated.items().forEach(u => u.value.cancel(state, dispatch)); this.updated = new Dictionary(); this.notifyListeners(); @@ -105,7 +101,6 @@ export class FormStateHandleFactory extends HandleFactory { } isDirty = (): boolean => { - console.log("IS DIRTY CALLED", this.updated); //debugger; return this.updated.items().length > 0; } @@ -132,9 +127,10 @@ export class FormStateHandleFactory extends HandleFactory { /*if(dependency.getDependencyString() === "beamline.elements") { debugger; }*/ + let fr = f(state); let type = this.schema.models[dependency.modelName][dependency.fieldName].type console.log("type", type); - let rawValue = revertDataStructure(f(state).value, getValueSelector(StoreTypes.FormState)); + let rawValue = revertDataStructure(fr.value, getValueSelector(StoreTypes.FormState)); console.log("rawValue", rawValue); let v = type.toModelValue(rawValue); console.log("value", v); diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 6f947ac68f..722b128fc5 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -89,7 +89,7 @@ export class DependencyReader { return x; } - getData = (su: SelectorUser): F[] => { + private getData = (su: SelectorUser): F[] => { let vs = getValueSelector(this.type); let newDeps = this.dependencies.flatMap(d => this.expandWildcard(d)); return newDeps.map(d => { diff --git a/react/src/hook/coupling.ts b/react/src/hook/coupling.ts new file mode 100644 index 0000000000..c25aaf512a --- /dev/null +++ b/react/src/hook/coupling.ts @@ -0,0 +1,17 @@ +import { useState } from "react"; + +export function useCoupledState(dependentValue, stateValOrFn: V | (() => V)): [V, (n: V) => void, boolean] { + let [dv, updateDv] = useState(dependentValue); + let [v, updateV] = useState(stateValOrFn); + + let updated = false; + + if(dependentValue !== dv) { + updateDv(dependentValue); + let nv = typeof stateValOrFn === "function" ? (stateValOrFn as Function)() : stateValOrFn; + updateV(nv); + updated = true; + } + + return [v, updateV, updated]; +} diff --git a/react/src/layout/arrange/waterfall.tsx b/react/src/layout/arrange/waterfall.tsx index 9ee1e67e5d..b05d29d32c 100644 --- a/react/src/layout/arrange/waterfall.tsx +++ b/react/src/layout/arrange/waterfall.tsx @@ -27,7 +27,14 @@ export class WaterfallLayout extends Layout { }); } - numBinsForBreakpoint(breakpoint: Breakpoint) { + formatValue = (v: number | string) => { + if(typeof(v) === 'number') { + return `${v}px`; + } + return v; + } + + numColumnsForBreakpoint(breakpoint: Breakpoint) { let bins = 1; // TODO: place default somewhere if(!this.config.breakpoints) { //return bins; @@ -46,105 +53,55 @@ export class WaterfallLayout extends Layout { return bins; } - - getMarginStyles = (): string => { - if(!this.config.gutters) { - return ""; - } - let formatValue = (v: number | string) => { - if(typeof(v) === 'number') { - return `${v}px`; - } - return v; - } - - let ret = {}; - if(this.config.gutters.horizontal) { - let h = formatValue(this.config.gutters.horizontal); - ret['margin-left'] = h; - ret['margin-right'] = h; - } - if(this.config.gutters.vertical) { - let v = formatValue(this.config.gutters.vertical); - ret['margin-top'] = v; - ret['margin-bottom'] = v; - } - - return Object.entries(ret).map(([name, value]) => `${name}: ${value}`).join("; ") - } + component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { + let c: JSX.Element[] = this.children.map((c, idx) => { + let LayoutComponent = c.component; + return + }); - waterfallBins = (props: { children: React.ReactNode }) => { let windowSize = useWindowSize(); let breakpoint = resolveBreakpoint(windowSize); - let numBins = this.numBinsForBreakpoint(breakpoint); + let numColumns = this.numColumnsForBreakpoint(breakpoint); - let bins: JSX.Element[] = []; - for(let b = 0; b < numBins; b++) { - bins.push(
- -
) - } + let containerRef = useRef(); - let gridStyle = { - "gridTemplateColumns": bins.map(() => `${(100/bins.length).toFixed(2)}%`).join(" "), - "gridTemplateRows": "1fr" + let fixupStyles = () => { + if(containerRef.current) { + let children = [...containerRef.current.children]; + children.map(c => c as HTMLElement).forEach(c => { + c.style.width = "100%"; + c.style.padding = "0"; + c.style.marginBottom = this.formatValue(this.config.gutters.vertical); + c.style.boxSizing = "border-box"; + c.style.breakInside = "avoid"; + }) + } } useEffect(() => { - if(!containerRef.current) { - return () => {}; - } - - if(!waterfallRef.current) { - return () => {}; - } - - let binEles = Array.from(waterfallRef.current.children); - - let container = containerRef.current; - // needs to be done this way, avoids mutating length during for loop - let children = Array.from(container.children); - let cleanups = []; - children.forEach((e, i) => { - let b = binEles[i % binEles.length]; - b.appendChild(e); - e.setAttribute("style", this.getMarginStyles()) - cleanups.push(() => { - container.appendChild(e); + if(containerRef.current) { + fixupStyles(); + let observer = new MutationObserver((mutations) => { + fixupStyles(); }) - }) - - return () => cleanups.forEach(c => c()) - }, [bins.length]) - - let waterfallRef = useRef(); - let containerRef = useRef(); + observer.observe(containerRef.current, { childList: true }); + return () => observer.disconnect(); + } + return () => {} + }) return ( <> -
- {bins} -
-
- {props.children} +
+ {c}
) - } - - component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { - - let c: JSX.Element[] = this.children.map((c, idx) => { - let LayoutComponent = c.component; - return - }); - - - let WaterfallBins = this.waterfallBins; - - return ( - {c} - ) }; } diff --git a/react/src/layout/beamline.scss b/react/src/layout/beamline.scss new file mode 100644 index 0000000000..38463cdb85 --- /dev/null +++ b/react/src/layout/beamline.scss @@ -0,0 +1,10 @@ +.beamline-item-header { + border-radius: 10px; + height: 18px; + background: #777; + color: #fff; + font-size: 12px; + font-weight: 700; + width: 70px; + text-align: center; +} diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 2f4a88d4af..125d69aba7 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -16,6 +16,10 @@ import { CRouteHelper } from "../utility/route"; import { Schema, SchemaLayout } from "../utility/schema"; import { Layout, LayoutProps } from "./layout"; import { createLayouts } from "./layouts"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import * as Icon from "@fortawesome/free-solid-svg-icons"; +import "./beamline.scss"; +import { useCoupledState } from "../hook/coupling"; export type BeamlineElement = { items: SchemaLayout[], @@ -40,15 +44,21 @@ export function BeamlineThumbnail(props: { name: string, iconSrc: string, onClic ) } -export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: Layout[] }, aliases: ArrayAliases, onClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { - let { baseElement, aliases, onClick, modalShown, onHideModal } = props; +export function BeamlineItem(props: { index: number, baseElement: BeamlineElement & { layouts: Layout[] }, header: string, aliases: ArrayAliases, onClick?: () => void, onDeleteClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { + let { index, baseElement, aliases, onClick, onDeleteClick, modalShown, onHideModal, header } = props; let routeHelper = useContext(CRouteHelper); let store = useStore(); let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); let handleFactory = useContext(CHandleFactory); - let [aliasedHandleFactory, _] = useState(new FormStateHandleFactory(schema, new HandleFactoryWithArrayAliases(schema, aliases, handleFactory))); + let createHandleFactory = () => new FormStateHandleFactory(schema, new HandleFactoryWithArrayAliases(schema, aliases, handleFactory)) + let [aliasedHandleFactory, _, indexChanged] = useCoupledState(index, createHandleFactory); + if(indexChanged) { + return <> + } + + let [isHover, updateIsHover] = useState(false); //aliasedHandleFactory.useUpdates(BeamlineItem); let dispatch = useDispatch(); let appWrapper = useContext(CAppWrapper); @@ -76,8 +86,17 @@ export function BeamlineItem(props: { baseElement: BeamlineElement & { layouts: let actionButtons = return ( -
- +
updateIsHover(true)} onMouseLeave={() => updateIsHover(false)} onClick={onClick}> +
{header}
+
+
{ e.stopPropagation(); if(onDeleteClick) onDeleteClick() }}> + +
+
+ +
+
+
{ //_cancel(); @@ -121,17 +140,12 @@ export class BeamlineLayout extends Layout { let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); - let [shownModal, updateShownModal] = useState(undefined); + let [shownModal, updateShownModal] = useState(undefined); let handle = formHandleFactory.createHandle>>(beamlineDependency, StoreTypes.FormState).hook(); // TODO: form or model? - console.log("beamline handle value", handle); - let addBeamlineElement = (element: BeamlineElement) => { - console.log("AAA"); let ms = schema.models[element.model]; - // TODO: use generic methods - let l = handle.value.value.length; let nextId = handle.value.value.reduce((prev, cur) => Math.max(prev, parseInt(cur.item.id.value) + 1), 1); let nextPos = handle.value.value.reduce((prev, cur) => Math.max(prev, parseFloat(cur.item.position.value) + 5), 0); let mv = newModelFromSchema(ms, { @@ -140,7 +154,6 @@ export class BeamlineLayout extends Layout { type: element.model }) - console.log("new beamline element mv", mv); let bv = [...handle.value.value]; bv.push({ item: formStateFromModelState(mv), @@ -151,7 +164,16 @@ export class BeamlineLayout extends Layout { touched: true, value: bv }, store.getState(), dispatch); - console.log("ADD ELEMENT"); + } + + let removeBeamlineElement = (index: number) => { + let bv = [...handle.value.value]; + bv.splice(index, 1); + handle.write({ + ...handle.value, + touched: true, + value: bv + }, store.getState(), dispatch); } let elementThumbnails = this.elements.map((e, i) => { @@ -168,14 +190,12 @@ export class BeamlineLayout extends Layout { return r[0]; } - console.log("MAPPING BEAMLINE ELEMENTS"); - let beamlineComponents = handle.value.value.map((e, i) => { + console.log(`BE ${i} = ${e.item.position.value}`) + let model = e.model; let ele: FormModelState = e.item; - console.log("ele", ele); let id = ele.id.value; - console.log("id", id); let baseElement = findBaseElementByModel(model); let aliases: ArrayAliases = [ @@ -191,7 +211,7 @@ export class BeamlineLayout extends Layout { ]; return ( - updateShownModal(i)} modalShown={shownModal === i} onHideModal={() => shownModal === i && updateShownModal(undefined)}/> + updateShownModal(id)} onDeleteClick={() => removeBeamlineElement(i)} modalShown={shownModal === id} onHideModal={() => shownModal === id && updateShownModal(undefined)}/> ) }) diff --git a/react/src/layout/form.tsx b/react/src/layout/form.tsx index abe5e102d5..bded62c8d6 100644 --- a/react/src/layout/form.tsx +++ b/react/src/layout/form.tsx @@ -13,12 +13,15 @@ import { CSchema } from "../data/appwrapper"; import { FormStateHandleFactory } from "../data/form"; import { CHandleFactory } from "../data/handle"; import { StoreTypes } from "../data/data"; +import { useCoupledState } from "../hook/coupling"; export function FormControllerElement(props: {children?: React.ReactNode}) { - console.log("FORM CTRL RENDER"); let schema = useContext(CSchema); let handleFactory = useContext(CHandleFactory); - let [formHandleFactory, _] = useState(new FormStateHandleFactory(schema, handleFactory)); + let [formHandleFactory, _, hfChanged] = useCoupledState(handleFactory, new FormStateHandleFactory(schema, handleFactory)); + if(hfChanged) { + return <> + } // TODO: form controller might need to "subscribe to updates" during save formHandleFactory.useUpdates(FormControllerElement); diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index ca245e1af3..00c672258a 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -32,7 +32,6 @@ export class PanelLayout extends Layout { } component = (props: LayoutProps<{}>) => { - console.log("PANEL RENDER"); let simulationInfoPromise = useContext(CSimulationInfoPromise); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; formHandleFactory.useUpdates(PanelLayout); diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index 0dc1a8d14b..10d17c0a85 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -19,7 +19,7 @@ import { ModelState } from "../store/models"; import { useShown } from "../hook/shown"; import { CHandleFactory, DependencyReader, useModelValue } from "../data/handle"; import { StoreTypes, ValueSelectors } from "../data/data"; -import { FormFieldState } from "../store/formState"; +import { interpolate } from "../utility/string"; export type ReportVisualProps = { data: L, model: ModelState }; @@ -44,12 +44,14 @@ export class AutoRunReportLayout extends Layout { } component = (props: LayoutProps<{}>) => { - let { report, dependencies } = this.config; + let { dependencies } = this.config; let simulationInfoPromise = useContext(CSimulationInfoPromise); let appName = useContext(CAppName); let schema = useContext(CSchema); + let handleFactory = useContext(CHandleFactory); let routeHelper = useContext(CRouteHelper); + let report = interpolate(this.config.report).withDependencies(handleFactory, StoreTypes.Models).raw(); let reportDependencies = dependencies.map(dependencyString => new Dependency(dependencyString)); let dependentValues = new DependencyReader(reportDependencies, StoreTypes.Models, schema).hook(); @@ -59,8 +61,6 @@ export class AutoRunReportLayout extends Layout { let [model, updateModel] = useState(undefined); useEffect(() => { - console.log("EFFECT"); - console.log("dependent values", dependentValues); updateSimulationData(undefined); simulationInfoPromise.then(({ models, simulationId }) => { updateModel(models[report]); diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index 3f7ca3dbfe..55d050a4ba 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -1,14 +1,14 @@ import React, { RefObject, useRef } from "react"; import { FunctionComponent, useContext, useState } from "react"; -import { ArrayAliases, HandleFactoryWithArrayAliases } from "../../data/alias"; +import { ArrayAliases, HandleFactoryOverrides, HandleFactoryWithArrayAliases, HandleFactoryWithOverrides } from "../../data/alias"; import { CSchema } from "../../data/appwrapper"; import { StoreTypes } from "../../data/data"; import { Dependency } from "../../data/dependency"; import { FormStateHandleFactory } from "../../data/form"; import { CHandleFactory } from "../../data/handle"; +import { useCoupledState } from "../../hook/coupling"; import { ArrayFieldState } from "../../store/common"; import { ModelState } from "../../store/models"; -import { Dictionary } from "../../utility/object"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; @@ -17,11 +17,24 @@ export type BeamlineWatchpointReportsConfig = { watchpointReportsDependency: string } -function BeamlineWatchpointItem(props: {child: Layout, aliases: ArrayAliases} & {[key: string]: any}) { - let { aliases, child } = props; +function BeamlineWatchpointItem(props: {beamlineIndex: number, aliases: ArrayAliases, overrides: HandleFactoryOverrides, child: Layout} & {[key: string]: any}) { + let { aliases, overrides, child, beamlineIndex } = props; let handleFactory = useContext(CHandleFactory); let schema = useContext(CSchema); - let [aliasedHandleFactory, _] = useState(new FormStateHandleFactory(schema, new HandleFactoryWithArrayAliases(schema, aliases, handleFactory))); + let createHandleFactory = () => new FormStateHandleFactory(schema, + new HandleFactoryWithArrayAliases(schema, aliases, + new HandleFactoryWithOverrides(schema, overrides, handleFactory) + ) + ) + let [aliasedHandleFactory, _, indexChanged] = useCoupledState(beamlineIndex, createHandleFactory); + console.log(`RENDER WATCHPOINT ITEM index=${beamlineIndex}`, aliases); + + if(indexChanged) { + console.log(`INDEX CHANGE`) + console.log("ALIASES", aliases); + return <> + } + aliasedHandleFactory.useUpdates(BeamlineWatchpointItem) let Comp = child.component; return ( @@ -32,33 +45,34 @@ function BeamlineWatchpointItem(props: {child: Layout, aliases: ArrayAliases} & } export class BeamlineWatchpointReports extends Layout { + private reportLayout: Layout; + + constructor(config: BeamlineWatchpointReportsConfig) { + super(config); + + this.reportLayout = LAYOUTS.getLayoutForSchema(createPanelConfig(new Dependency("iteration.index"), new Dependency("beamlineElement.position"), new Dependency("beamlineElement.id"))) + } + component: FunctionComponent<{ [key: string]: any; }> = (props) => { let watchpointReportsDependency = new Dependency(this.config.watchpointReportsDependency); let beamlineDependency = new Dependency(this.config.beamlineDependency); let handleFactory = useContext(CHandleFactory); let reportsHandle = handleFactory.createHandle(watchpointReportsDependency, StoreTypes.Models).hook(); let elementsHandle = handleFactory.createHandle(beamlineDependency, StoreTypes.Models).hook(); - let reportsValue = reportsHandle.value as ArrayFieldState; let elementsValue = elementsHandle.value as ArrayFieldState; let findElementIndexById = (id: any) => elementsValue.findIndex(e => e.item.id == id); - let findElementById = (id: any) => elementsValue[findElementIndexById(id)] - - - let reportLayoutsRef: RefObject> = useRef(new Dictionary()); + let findElementById = (id: any) => elementsValue[findElementIndexById(id)]; - reportsValue.forEach((report, index) => { - let id = `${report.item.id}`; - let ele = findElementById(id); - if(!reportLayoutsRef.current.contains(id)) { - let cfg = createPanelConfig(`watchpointReport${index}`, new Dependency("beamlineElement.position")); - reportLayoutsRef.current.put(id, LAYOUTS.getLayoutForSchema(cfg)); - } - }) + console.log("WATCHPOINT REPORTS VALUE", reportsHandle.value); - let reportElements = reportLayoutsRef.current.items().map((e, index) => { - let beamlineIndex = findElementIndexById(e.key); - let beamlineElement = findElementById(e.key); + let comps = (reportsHandle.value as ArrayFieldState).map(i => i.item).map((report, index) => { + let id = report.id; + console.log("ID", id); + let beamlineIndex = findElementIndexById(id); + console.log("BEAMLINE INDEX", beamlineIndex); + let beamlineElement = findElementById(id); + console.log("BEAMLINE ELEMENT", beamlineElement); let aliases: ArrayAliases = [ { realDataLocation: { @@ -79,22 +93,30 @@ export class BeamlineWatchpointReports extends Layout - - + ) }) + console.log("ELEMENTS", comps); + return (<>{ - reportElements + comps }); }; } -function createPanelConfig(reportName: string, titleDep: Dependency) { +function createPanelConfig(indexDep: Dependency, titleDep: Dependency, idDep: Dependency) { return { "layout": "panel", "config": { @@ -103,7 +125,7 @@ function createPanelConfig(reportName: string, titleDep: Dependency) { { "layout": "autoRunReport", "config": { - "report": reportName, + "report": `watchpointReport$(${indexDep.getDependencyString()})`, "dependencies": [ "beamline.*", "bendingMagnet.*", diff --git a/react/src/store/common.ts b/react/src/store/common.ts index 6230ed07e9..28f3134a3d 100644 --- a/react/src/store/common.ts +++ b/react/src/store/common.ts @@ -39,7 +39,6 @@ export const makeSlice = (sliceName: string): { initialState: {}, reducers: { updateModel: (state, {payload: {name, value}}: {payload: ModelStateUpdate}) => { - console.log(`UPDATE MODEL ${name} IN ${sliceName}`); (state[name] as any) = value; } } diff --git a/react/src/utility/object.ts b/react/src/utility/object.ts index 96c817dd8a..c719580b40 100644 --- a/react/src/utility/object.ts +++ b/react/src/utility/object.ts @@ -28,9 +28,17 @@ export class Dictionary { } items = (): KeyValuePair[] => { - return this.records; + return [...this.records]; } + remove = (key: K): V => { + let idx = this.records.findIndex(this.comparator(key)); + if(idx >= 0) { + return this.records.splice(idx, 1)[0].value; + } + return undefined; + } + put = (key: K, value: V): void => { let idx = this.records.findIndex(this.comparator(key)); if(idx >= 0) { @@ -41,4 +49,8 @@ export class Dictionary { value }) } + + clear = (): void => { + this.records = []; + } } diff --git a/react/src/utility/string.ts b/react/src/utility/string.ts index aaee74cee9..318ef2d46f 100644 --- a/react/src/utility/string.ts +++ b/react/src/utility/string.ts @@ -1,4 +1,4 @@ -import { getValueSelector, StoreType, StoreTypes } from "../data/data"; +import { getValueSelector, StoreType } from "../data/data"; import { Dependency } from "../data/dependency"; import { HandleFactory } from "../data/handle"; @@ -91,6 +91,7 @@ export function titleCaseString(str: string): string { }).join(" "); } +// https://stackoverflow.com/a/15710692 export function hashCode(s: string): number { return s.split("").reduce(function(a, b) { a = ((a << 5) - a) + b.charCodeAt(0); From 53f649e85aaa25591fe855622c002a83b8495eb9 Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 21 Apr 2023 19:16:28 +0000 Subject: [PATCH 28/68] add middleware to schema --- react/src/component/simulation.tsx | 94 ++----------------- react/src/data/middleware/middleware.ts | 16 ++++ react/src/data/middleware/shadow/beamline.ts | 54 +++++++++++ .../src/data/middleware/shadow/watchpoint.ts | 52 ++++++++++ react/src/utility/schema.ts | 24 ++++- .../static/react-json/shadow-schema.json | 17 ++++ 6 files changed, 164 insertions(+), 93 deletions(-) create mode 100644 react/src/data/middleware/middleware.ts create mode 100644 react/src/data/middleware/shadow/beamline.ts create mode 100644 react/src/data/middleware/shadow/watchpoint.ts diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 788449168f..019f11711c 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -9,7 +9,6 @@ import React, { useContext } from "react"; import { - modelSelectors, modelActions, ModelState, modelsSlice @@ -29,12 +28,13 @@ import { useSetup } from "../hook/setup"; import { Portal } from "./reusable/portal"; import { downloadAs, getAttachmentFileName } from "../utility/download"; import { Provider, useDispatch, useStore } from "react-redux"; -import { ArrayFieldState, StoreState } from "../store/common"; -import { configureStore, Middleware } from "@reduxjs/toolkit"; -import { formActions, formSelectors, formStatesSlice } from "../store/formState"; +import { StoreState } from "../store/common"; +import { configureStore } from "@reduxjs/toolkit"; +import { formStatesSlice } from "../store/formState"; import { BaseHandleFactory, CHandleFactory } from "../data/handle"; -import { getValueSelector, newModelFromSchema, StoreType, StoreTypes } from "../data/data"; +import { StoreTypes } from "../data/data"; import { useCoupledState } from "../hook/coupling"; +import { middlewaresForSchema } from "../data/middleware/middleware"; export type SimulationInfoRaw = { models: StoreState, @@ -49,94 +49,12 @@ export type SimulationInfo = SimulationInfoRaw & { function SimulationStoreInitializer(props: {[key: string]: any}) { let schema = useContext(CSchema); - let shadowBeamlineWatchpointReportsMiddleware: Middleware = store => next => action => { - if(action.type === "models/updateModel") { - let { name, value } = action.payload; - if(name === "beamline") { - let watchpointReportsModel: ModelState = modelSelectors.selectModel("watchpointReports")(store.getState()); - if(watchpointReportsModel) { - let watchpointReports = watchpointReportsModel.reports as ArrayFieldState; - let bv: ArrayFieldState = value.elements; - let findWatchpointReportById = (id) => watchpointReports.find(e => e.item.id === id); - let reportsValue = bv.filter(e => e.model == "watch").map(e => { - let id = e.item.id; - let watchpointReport = findWatchpointReportById(id); // TODO: these ids need to be made more unique or errors will occur - if(!watchpointReport) { - watchpointReport = { - item: newModelFromSchema(schema.models["watchpointReport"], { id }), - model: "watchpointReport" - }; - } - - return { - report: watchpointReport, - position: e.item.position as number - } - }).sort((e1, e2) => e1.position - e2.position).map(e => e.report); - - store.dispatch(modelActions.updateModel({ name: "watchpointReports", value: { - reports: reportsValue - }})); - } - } - } - return next(action); - } - - let shadowBeamlineSortingMiddleware: Middleware = store => next => action => { - let sortValues = (v, vs) => v.sort((a, b) => { - return parseFloat(vs(a.item.position)) - parseFloat(vs(b.item.position)) - }); - - if(action.type === "models/updateModel") { - let { name, value } = action.payload; - if(name === "beamline") { - let vs = getValueSelector(StoreTypes.Models) - let v = vs(value.elements); - let nv = sortValues(v, vs); - - let formBeamlineModel: ModelState = formSelectors.selectModel("beamline")(store.getState()); - if(formBeamlineModel !== undefined) { - let fvs = getValueSelector(StoreTypes.FormState); - console.log("fbm", formBeamlineModel); - store.dispatch(formActions.updateModel({ - name, - value: { - ...formBeamlineModel, - elements: { - ...(formBeamlineModel.elements as any), - value: sortValues([...fvs(formBeamlineModel.elements as any)], fvs) - } - } - })) - } - - - return next(modelActions.updateModel({ - name, - value: { - ...value, - elements: nv - } - })); - } - } - - return next(action); - } - - // TODO make server saving middleware - - const [modelsStore, _] = useState(() => configureStore({ reducer: { [modelsSlice.name]: modelsSlice.reducer, [formStatesSlice.name]: formStatesSlice.reducer, }, - middleware: [ - shadowBeamlineWatchpointReportsMiddleware, - shadowBeamlineSortingMiddleware - ] + middleware: [...middlewaresForSchema(schema)] })); return ( diff --git a/react/src/data/middleware/middleware.ts b/react/src/data/middleware/middleware.ts new file mode 100644 index 0000000000..0c38402ea1 --- /dev/null +++ b/react/src/data/middleware/middleware.ts @@ -0,0 +1,16 @@ +import { Middleware } from "redux"; +import { Schema } from "../../utility/schema"; +import { shadowBeamlineSortingMiddleware } from "./shadow/beamline"; +import { shadowBeamlineWatchpointReportsMiddleware } from "./shadow/watchpoint"; + +export type ConfigurableMiddleware = (config: C, schema: Schema) => Middleware + +export const Middlewares: {[key: string]: ConfigurableMiddleware} = { + shadowWatchpointsFromBeamline: shadowBeamlineWatchpointReportsMiddleware, + shadowBeamlineSorting: shadowBeamlineSortingMiddleware +} + +export function middlewaresForSchema(schema: Schema): Middleware[] { + console.log("schema middleware", schema.middleware); + return (schema.middleware || []).map(sm => Middlewares[sm.type](sm.config, schema)); +} diff --git a/react/src/data/middleware/shadow/beamline.ts b/react/src/data/middleware/shadow/beamline.ts new file mode 100644 index 0000000000..0fd3f2d216 --- /dev/null +++ b/react/src/data/middleware/shadow/beamline.ts @@ -0,0 +1,54 @@ +import { formSelectors, formActions } from "../../../store/formState"; +import { ModelState, modelActions } from "../../../store/models"; +import { getValueSelector, StoreTypes } from "../../data"; +import { ConfigurableMiddleware } from "../middleware"; +import { Dependency } from "../../dependency"; + +export type BeamlineSortingMiddlewareConfig = { + beamlineDependency: string, +} + +export const shadowBeamlineSortingMiddleware: ConfigurableMiddleware = (config, schema) => { + let beamDep = new Dependency(config.beamlineDependency); + + return store => next => action => { + let sortValues = (v, vs) => v.sort((a, b) => { + return parseFloat(vs(a.item.position)) - parseFloat(vs(b.item.position)) + }); + + if(action.type === "models/updateModel") { + let { name, value } = action.payload; + if(name === beamDep.modelName) { + let vs = getValueSelector(StoreTypes.Models) + let v = vs(value.elements); + let nv = sortValues(v, vs); + + let formBeamlineModel: ModelState = formSelectors.selectModel(beamDep.modelName)(store.getState()); + if(formBeamlineModel !== undefined) { + let fvs = getValueSelector(StoreTypes.FormState); + store.dispatch(formActions.updateModel({ + name, + value: { + ...formBeamlineModel, + [beamDep.fieldName]: { + ...(formBeamlineModel[beamDep.fieldName] as any), + value: sortValues([...fvs(formBeamlineModel[beamDep.fieldName] as any)], fvs) + } + } + })) + } + + + return next(modelActions.updateModel({ + name, + value: { + ...value, + [beamDep.fieldName]: nv + } + })); + } + } + + return next(action); + } +} diff --git a/react/src/data/middleware/shadow/watchpoint.ts b/react/src/data/middleware/shadow/watchpoint.ts new file mode 100644 index 0000000000..10f57b0a28 --- /dev/null +++ b/react/src/data/middleware/shadow/watchpoint.ts @@ -0,0 +1,52 @@ +import { ArrayFieldState } from "../../../store/common"; +import { ModelState, modelSelectors, modelActions } from "../../../store/models"; +import { Schema } from "../../../utility/schema"; +import { newModelFromSchema } from "../../data"; +import { ConfigurableMiddleware } from "../middleware"; +import { Dependency } from "../../dependency"; + +export type WatchpointReportsMiddlewareConfig = { + beamlineDependency: string, + watchpointReportsDependency: string, + watchpointModelName: string, + watchpointReportModelName: string +} + +export const shadowBeamlineWatchpointReportsMiddleware: ConfigurableMiddleware = (config: WatchpointReportsMiddlewareConfig, schema: Schema) => { + let beamDep = new Dependency(config.beamlineDependency); + let watchRepDep = new Dependency(config.watchpointReportsDependency); + + return store => next => action => { + if(action.type === "models/updateModel") { + let { name, value } = action.payload; + if(name === beamDep.modelName) { + let watchpointReportsModel: ModelState = modelSelectors.selectModel(watchRepDep.modelName)(store.getState()); + if(watchpointReportsModel) { + let watchpointReports = watchpointReportsModel[watchRepDep.fieldName] as ArrayFieldState; + let bv: ArrayFieldState = value[beamDep.fieldName]; + let findWatchpointReportById = (id) => watchpointReports.find(e => e.item.id === id); + let reportsValue = bv.filter(e => e.model == config.watchpointModelName).map(e => { + let id = e.item.id; + let watchpointReport = findWatchpointReportById(id); // TODO: these ids need to be made more unique or errors will occur + if(!watchpointReport) { + watchpointReport = { + item: newModelFromSchema(schema.models[config.watchpointReportModelName], { id }), + model: config.watchpointReportModelName + }; + } + + return { + report: watchpointReport, + position: e.item.position as number + } + }).sort((e1, e2) => e1.position - e2.position).map(e => e.report); + + store.dispatch(modelActions.updateModel({ name: watchRepDep.modelName, value: { + [watchRepDep.fieldName]: reportsValue + }})); + } + } + } + return next(action); + } +} diff --git a/react/src/utility/schema.ts b/react/src/utility/schema.ts index b5f435d934..5b35c76234 100644 --- a/react/src/utility/schema.ts +++ b/react/src/utility/schema.ts @@ -32,13 +32,19 @@ export type SchemaRoutesJson = { [key: string]: string } +export type SchemaMiddlewareJson = { + type: string, + config: {[key: string]: any} +} + export type SchemaJson = { constants: {[key: string]: any}, type: {[typeName: string]: SchemaTypeJson}, model: SchemaModelsJson, view: SchemaLayoutJson[], route: SchemaRoutesJson, - reactRoute: SchemaRoutesJson + reactRoute: SchemaRoutesJson, + middleware: SchemaMiddlewareJson[] } export type SchemaLayout = SchemaLayoutJson; @@ -64,19 +70,22 @@ export type SchemaRoutes = { [key: string]: string } +export type SchemaMiddleware = SchemaMiddlewareJson; + export type Schema = { constants: {[key: string]: any}, models: SchemaModels, views: SchemaLayout[], route: SchemaRoutes, - reactRoute: SchemaRoutes + reactRoute: SchemaRoutes, + middleware: SchemaMiddleware[] } export const getAppCombinedSchema = (appName: string): Promise => { return new Promise((resolve, reject) => { Promise.all([ fetch(`/static/react-json/common-schema.json`), - fetch(`/static/react-json/${appName}-schema.json`) + fetch(`/static/react-json/${appName.toLocaleLowerCase()}-schema.json`) ]).then(([commonResp, appResp]) => { Promise.all([ commonResp.json(), @@ -121,7 +130,11 @@ export function mergeSchemaJson(original: SchemaJson, overrides: SchemaJson): Sc reactRoute: { ...(original.reactRoute || {}), ...(overrides.reactRoute || {}) - } + }, + middleware: [ + ...(original.middleware || []), + ...(overrides.middleware || []) + ] } } @@ -178,6 +191,7 @@ export function compileSchemaFromJson(schemaObj: SchemaJson): Schema { views: schemaObj.view, models, route: schemaObj.route, - reactRoute: schemaObj.reactRoute + reactRoute: schemaObj.reactRoute, + middleware: schemaObj.middleware } } diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index c216048704..cbd52cd469 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -3395,6 +3395,23 @@ } } }, + "middleware": [ + { + "type": "shadowWatchpointsFromBeamline", + "config": { + "beamlineDependency": "beamline.elements", + "watchpointReportsDependency": "watchpointReports.reports", + "watchpointModelName": "watch", + "watchpointReportModelName": "watchpointReport" + } + }, + { + "type": "shadowBeamlineSorting", + "config": { + "beamlineDependency": "beamline.elements" + } + } + ], "view": [ { "layout": "navbarModalButton", From 478bcb6f8f356f10cde7533b12f9080d3b7c544c Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 21 Apr 2023 19:32:04 +0000 Subject: [PATCH 29/68] fixup waterfall --- react/src/layout/arrange/column.tsx | 4 ---- react/src/layout/arrange/waterfall.tsx | 5 +++-- sirepo/package_data/static/react-json/genesis-schema.json | 2 ++ sirepo/package_data/static/react-json/jspec-schema.json | 2 ++ sirepo/package_data/static/react-json/shadow-schema.json | 2 ++ 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/react/src/layout/arrange/column.tsx b/react/src/layout/arrange/column.tsx index 8b1edfb45e..a8e0e661a7 100644 --- a/react/src/layout/arrange/column.tsx +++ b/react/src/layout/arrange/column.tsx @@ -17,10 +17,6 @@ export class ColumnLayout extends Layout { this.child = LAYOUTS.getLayoutForSchema(config.item); } - getFormDependencies(): Dependency[] { - return this.child.getFormDependencies(); - } - component: FunctionComponent<{ [key: string]: any; }> = (props) => { let LayoutComponent = this.child.component; return ( diff --git a/react/src/layout/arrange/waterfall.tsx b/react/src/layout/arrange/waterfall.tsx index b05d29d32c..1b265de58d 100644 --- a/react/src/layout/arrange/waterfall.tsx +++ b/react/src/layout/arrange/waterfall.tsx @@ -14,7 +14,8 @@ export type WaterfallConfig = { gutters?: { vertical?: string | number, horizontal?: string | number - } + }, + padding: string } export class WaterfallLayout extends Layout { @@ -96,7 +97,7 @@ export class WaterfallLayout extends Layout {
{c} diff --git a/sirepo/package_data/static/react-json/genesis-schema.json b/sirepo/package_data/static/react-json/genesis-schema.json index 43bcde9ac4..29174031a2 100644 --- a/sirepo/package_data/static/react-json/genesis-schema.json +++ b/sirepo/package_data/static/react-json/genesis-schema.json @@ -1204,6 +1204,7 @@ "horizontal": ".5em", "vertical": ".5em" }, + "padding": ".5em", "items": [ { "layout": "panel", @@ -1825,6 +1826,7 @@ "horizontal": ".5em", "vertical": ".5em" }, + "padding": ".5em", "items": [ { "layout": "panel", diff --git a/sirepo/package_data/static/react-json/jspec-schema.json b/sirepo/package_data/static/react-json/jspec-schema.json index 5e8675c8b1..d7b4d724d3 100644 --- a/sirepo/package_data/static/react-json/jspec-schema.json +++ b/sirepo/package_data/static/react-json/jspec-schema.json @@ -1290,6 +1290,7 @@ "horizontal": ".5em", "vertical": ".5em" }, + "padding": ".5em", "items": [ { "layout": "panel", @@ -1550,6 +1551,7 @@ "horizontal": ".5em", "vertical": ".5em" }, + "padding": ".5em", "items": [ { "layout": "panel", diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index cbd52cd469..fa37fab0c8 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -3455,6 +3455,7 @@ "horizontal": ".5em", "vertical": ".5em" }, + "padding": ".5em", "items": [ { "layout": "panel", @@ -5055,6 +5056,7 @@ "horizontal": ".5em", "vertical": ".5em" }, + "padding": ".5em", "items": [ { "layout": "panel", From 0665f886d600613eb207dd399d1619bb2ad04b7b Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 21 Apr 2023 19:39:29 +0000 Subject: [PATCH 30/68] remove console logs --- react/src/component/reusable/form.tsx | 1 - react/src/component/simulation.tsx | 1 - react/src/layout/beamline.tsx | 3 --- react/src/layout/shadow/beamlineWatchpointReports.tsx | 10 ---------- 4 files changed, 15 deletions(-) diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 6a0e090602..bbb96e8144 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -101,7 +101,6 @@ export function FormStateInitializer(props) { value: mapProperties(value, (_, fv) => initialFormStateFromValue(fv)) })); }); - console.log("formState", store.getState()[formStatesSlice.name]); updateHasInit(true); }) diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index b11533aa88..7cd100c2b5 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -272,7 +272,6 @@ export function SimulationOuter(props) { let handleFactory = useContext(CHandleFactory); let store = useStore(); - console.log("models", store.getState()[StoreTypes.Models.name]); let simNameHandle = handleFactory.createHandle(new Dependency("simulation.name"), StoreTypes.Models).hook(); useEffect(() => { diff --git a/react/src/layout/beamline.tsx b/react/src/layout/beamline.tsx index 125d69aba7..e45d5c8a87 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/beamline.tsx @@ -128,7 +128,6 @@ export class BeamlineLayout extends Layout { } component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { - console.log("RENDER BEAMLINE"); let routeHelper = useContext(CRouteHelper); let store = useStore(); let simulationInfoPromise = useContext(CSimulationInfoPromise); @@ -191,8 +190,6 @@ export class BeamlineLayout extends Layout { } let beamlineComponents = handle.value.value.map((e, i) => { - console.log(`BE ${i} = ${e.item.position.value}`) - let model = e.model; let ele: FormModelState = e.item; let id = ele.id.value; diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index 55d050a4ba..de41c1a64c 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -27,11 +27,8 @@ function BeamlineWatchpointItem(props: {beamlineIndex: number, aliases: ArrayAli ) ) let [aliasedHandleFactory, _, indexChanged] = useCoupledState(beamlineIndex, createHandleFactory); - console.log(`RENDER WATCHPOINT ITEM index=${beamlineIndex}`, aliases); if(indexChanged) { - console.log(`INDEX CHANGE`) - console.log("ALIASES", aliases); return <> } @@ -64,15 +61,10 @@ export class BeamlineWatchpointReports extends Layout elementsValue.findIndex(e => e.item.id == id); let findElementById = (id: any) => elementsValue[findElementIndexById(id)]; - console.log("WATCHPOINT REPORTS VALUE", reportsHandle.value); - let comps = (reportsHandle.value as ArrayFieldState).map(i => i.item).map((report, index) => { let id = report.id; - console.log("ID", id); let beamlineIndex = findElementIndexById(id); - console.log("BEAMLINE INDEX", beamlineIndex); let beamlineElement = findElementById(id); - console.log("BEAMLINE ELEMENT", beamlineElement); let aliases: ArrayAliases = [ { realDataLocation: { @@ -108,8 +100,6 @@ export class BeamlineWatchpointReports extends Layout{ comps }); From 1e25abd51add5ee2ab0d8270e3d07fd8dc268133 Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 21 Apr 2023 22:46:58 +0000 Subject: [PATCH 31/68] fix schema conversion script and begin to convert schema for madx --- react/utility/convertschema.ts | 3 + .../static/react-json/madx-schema.json | 8919 +++++++++++++++++ 2 files changed, 8922 insertions(+) create mode 100644 sirepo/package_data/static/react-json/madx-schema.json diff --git a/react/utility/convertschema.ts b/react/utility/convertschema.ts index 31776687a6..671dd46163 100644 --- a/react/utility/convertschema.ts +++ b/react/utility/convertschema.ts @@ -192,6 +192,9 @@ function convertSchema(schema: OldSchema) { function convertModel(model: OldSchemaModel): SchemaModelJson { let newModel = {}; for(let [fieldName, field] of Object.entries(model)) { + if(field === undefined) { + continue; + } let [name, typeString, defaultValue, description, min, max] = field; newModel[fieldName] = { displayName: name, diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json new file mode 100644 index 0000000000..5e552b89e0 --- /dev/null +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -0,0 +1,8919 @@ +{ + "model": { + "beamline": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + } + }, + "bunch": { + "beamDefinition": { + "displayName": "Beam Definition", + "type": "BeamDefinition", + "defaultValue": "energy" + }, + "matchTwissParameters": { + "displayName": "Match Twiss Parameters", + "type": "Boolean", + "defaultValue": "0", + "description": "Use twiss parameters computed from the selected beamline" + }, + "numberOfParticles": { + "displayName": "Number Of Particles", + "type": "Integer", + "defaultValue": 1000, + "description": "Number of particles to track.", + "min": 1, + "max": 10000 + }, + "randomSeed": { + "displayName": "Random Number Seed", + "type": "Integer", + "defaultValue": 123456789, + "description": "The seed for the random number generator for particles" + }, + "betx": { + "displayName": "Horizontal Beta [m]", + "type": "Float", + "defaultValue": 1 + }, + "bety": { + "displayName": "Vertical Beta [m]", + "type": "Float", + "defaultValue": 1 + }, + "alfx": { + "displayName": "Horizontal Alpha", + "type": "Float", + "defaultValue": 0 + }, + "alfy": { + "displayName": "Vertical Alpha", + "type": "Float", + "defaultValue": 0 + }, + "px": { + "displayName": "Horizontal Canonical Momentum of $p_x$", + "type": "Float", + "defaultValue": 0 + }, + "py": { + "displayName": "Vertical Canonical Momentum of $p_y$", + "type": "Float", + "defaultValue": 0 + }, + "x": { + "displayName": "Horizontal Centroid [m]", + "type": "Float", + "defaultValue": 0 + }, + "y": { + "displayName": "Vertical Centroid [m]", + "type": "Float", + "defaultValue": 0 + } + }, + "simulation": { + "enableParticleTracking": { + "displayName": "Particle Tracking", + "type": "Boolean", + "defaultValue": "1" + }, + "visualizationBeamlineId": { + "displayName": "Beamline", + "type": "LatticeBeamlineList", + "defaultValue": "" + }, + "commandTemplate": { + "displayName": "Template", + "type": "CommandTemplate", + "defaultValue": "particle" + }, + "computeTwissFromParticles": { + "displayName": "Compute Twiss From Particles", + "type": "Boolean", + "defaultValue": "0" + } + }, + "beamlineReport": { + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "bunchReport": { + "x": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "y": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "histogramBins": { + "displayName": "Histogram Bins", + "type": "Integer", + "defaultValue": 200 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "afmhot" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "command_beam": { + "particle": { + "displayName": "PARTICLE", + "type": "ParticleType", + "defaultValue": "positron", + "description": "The name of particles in the beam." + }, + "mass": { + "displayName": "MASS [GeV]", + "type": "RPNValue", + "defaultValue": 0.0005109989461, + "description": "The restmass of the particles in the beam." + }, + "charge": { + "displayName": "CHARGE [qp]", + "type": "RPNValue", + "defaultValue": 1, + "description": "The electrical charge of the particles in the beam in units of the proton charge" + }, + "energy": { + "displayName": "ENERGY [GeV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Total energy per particle." + }, + "pc": { + "displayName": "PC [GeV/c]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Momentum per particle." + }, + "gamma": { + "displayName": "GAMMA", + "type": "RPNValue", + "defaultValue": 0, + "description": "Relativistic factor, ie the ratio between total energy and rest energy of the particles." + }, + "beta": { + "displayName": "BETA [v/c]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Ratio between the speed of the particles and the speed of light." + }, + "brho": { + "displayName": "BRHO [P/abs(q)]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Magnetic rigidity of the particles." + }, + "ex": { + "displayName": "EX [m]", + "type": "RPNValue", + "defaultValue": 1, + "description": "The horizontal emittance." + }, + "exn": { + "displayName": "EXN", + "type": "RPNValue", + "defaultValue": 0, + "description": "The normalised horizontal emittance." + }, + "ey": { + "displayName": "EY [m]", + "type": "RPNValue", + "defaultValue": 1, + "description": "The vertical emittance." + }, + "eyn": { + "displayName": "EYN", + "type": "RPNValue", + "defaultValue": 0, + "description": "The normalised vertical emittance." + }, + "et": { + "displayName": "ET [m]", + "type": "RPNValue", + "defaultValue": 0.001, + "description": "The longitudinal emittance $\\epsilon_t$" + }, + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Attaches the beam command to a specific sequence." + }, + "sigt": { + "displayName": "SIGT [m]", + "type": "RPNValue", + "defaultValue": 1, + "description": "The bunch length $c\\space \\sigma_t$." + }, + "sige": { + "displayName": "SIGE", + "type": "RPNValue", + "defaultValue": 0.001, + "description": "The relative energy spread $\\sigma_E / E$." + }, + "kbunch": { + "displayName": "KBUNCH", + "type": "Integer", + "defaultValue": 1, + "description": "The number of particle bunches in the machine." + }, + "npart": { + "displayName": "NPART", + "type": "Integer", + "defaultValue": 1, + "description": "The number of particles per bunch." + }, + "bcurrent": { + "displayName": "BCURRENT", + "type": "RPNValue", + "defaultValue": 0, + "description": "The bunch current." + }, + "bunched": { + "displayName": "BUNCHED", + "type": "Boolean", + "defaultValue": "1", + "description": "The beam is treated as bunched whenever this makes sense." + }, + "radiate": { + "displayName": "RADIATE", + "type": "Boolean", + "defaultValue": "0", + "description": "Synchrotron radiation is considered in all bipolar magnets." + }, + "bv": { + "displayName": "BV", + "type": "Integer", + "defaultValue": 1, + "description": "The direction of the particle movement in a beam line." + } + }, + "command_beta0": { + "betx": { + "displayName": "BETX [m]", + "type": "RPNValue", + "defaultValue": 0 + }, + "alfx": { + "displayName": "ALFX", + "type": "RPNValue", + "defaultValue": 0 + }, + "mux": { + "displayName": "MUX", + "type": "RPNValue", + "defaultValue": 0 + }, + "bety": { + "displayName": "BETY", + "type": "RPNValue", + "defaultValue": 0 + }, + "alfy": { + "displayName": "ALFY", + "type": "RPNValue", + "defaultValue": 0 + }, + "muy": { + "displayName": "MUY", + "type": "RPNValue", + "defaultValue": 0 + }, + "x": { + "displayName": "X", + "type": "RPNValue", + "defaultValue": 0 + }, + "px": { + "displayName": "PX", + "type": "RPNValue", + "defaultValue": 0 + }, + "y": { + "displayName": "Y", + "type": "RPNValue", + "defaultValue": 0 + }, + "py": { + "displayName": "PY", + "type": "RPNValue", + "defaultValue": 0 + }, + "t": { + "displayName": "T", + "type": "RPNValue", + "defaultValue": 0 + }, + "pt": { + "displayName": "PT", + "type": "RPNValue", + "defaultValue": 0 + }, + "dx": { + "displayName": "DX", + "type": "RPNValue", + "defaultValue": 0 + }, + "dpx": { + "displayName": "DPX", + "type": "RPNValue", + "defaultValue": 0 + }, + "dy": { + "displayName": "DY", + "type": "RPNValue", + "defaultValue": 0 + }, + "dpy": { + "displayName": "DPY", + "type": "RPNValue", + "defaultValue": 0 + }, + "wx": { + "displayName": "WX", + "type": "RPNValue", + "defaultValue": 0 + }, + "phix": { + "displayName": "PHIX", + "type": "RPNValue", + "defaultValue": 0 + }, + "dmux": { + "displayName": "DMUX", + "type": "RPNValue", + "defaultValue": 0 + }, + "wy": { + "displayName": "WY", + "type": "RPNValue", + "defaultValue": 0 + }, + "phiy": { + "displayName": "PHIY", + "type": "RPNValue", + "defaultValue": 0 + }, + "dmuy": { + "displayName": "DUMY", + "type": "RPNValue", + "defaultValue": 0 + }, + "ddx": { + "displayName": "DDX", + "type": "RPNValue", + "defaultValue": 0 + }, + "ddpx": { + "displayName": "DDPX", + "type": "RPNValue", + "defaultValue": 0 + }, + "ddy": { + "displayName": "DDY", + "type": "RPNValue", + "defaultValue": 0 + }, + "ddpy": { + "displayName": "DDPY", + "type": "RPNValue", + "defaultValue": 0 + }, + "r11": { + "displayName": "R11", + "type": "RPNValue", + "defaultValue": 0 + }, + "r12": { + "displayName": "R12", + "type": "RPNValue", + "defaultValue": 0 + }, + "r21": { + "displayName": "R21", + "type": "RPNValue", + "defaultValue": 0 + }, + "r22": { + "displayName": "R22", + "type": "RPNValue", + "defaultValue": 0 + }, + "energy": { + "displayName": "ENERGY", + "type": "RPNValue", + "defaultValue": 0 + } + }, + "command_call": { + "file": { + "displayName": "FILE", + "type": "String", + "defaultValue": "", + "description": "The named file is read until a RETURN statement is encountered, or until the EOF." + } + }, + "command_constraint": { + "sequence": { + "displayName": "SEQUENCE", + "type": "LatticeBeamlineList", + "defaultValue": "", + "description": "Sequence for which the constraint applies" + }, + "range": { + "displayName": "RANGE", + "type": "String", + "defaultValue": "", + "description": "Position where the constraint must be satisfied" + }, + "alfx": { + "displayName": "ALFX", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Correlation function $\\alpha_x$" + }, + "alfy": { + "displayName": "ALFY", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Correlation function $\\alpha_y$" + }, + "betx": { + "displayName": "BETX [m]", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Amplitude function $\\beta_x$" + }, + "bety": { + "displayName": "BETY [m]", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Amplitude function $\\beta_y$" + }, + "dpx": { + "displayName": "DPX", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Dispersion of $p_x$: $D_{px}$" + }, + "dpy": { + "displayName": "DPY", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Dispersion of $p_y$: $D_{py}$" + }, + "dx": { + "displayName": "DX [m]", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Dispersion of $x$: $D_x$" + }, + "dy": { + "displayName": "DY [m]", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Dispersion of $y$: $D_y$" + }, + "mux": { + "displayName": "MUX [2$\\pi$]", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Phase function of $\\mu_x$" + }, + "muy": { + "displayName": "MUY [2$\\pi$]", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Phase function of $\\mu_y$" + }, + "px": { + "displayName": "PX", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Horizontal canonical momentum of $p_x$" + }, + "py": { + "displayName": "PY", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Horizontal canonical momentum of $p_y$" + }, + "x": { + "displayName": "X", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Canonical coordinate $x$" + }, + "y": { + "displayName": "Y", + "type": "OptionalRPNValue", + "defaultValue": null, + "description": "Canonical coordinate $y$" + } + }, + "command_ealign": { + "dx": { + "displayName": "DX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The misalignment in the x-direction for the entry of the beam element." + }, + "dy": { + "displayName": "DY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The misalignment in the y-direction for the entry of the beam element." + }, + "ds": { + "displayName": "DS [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The misalignment in the s-direction for the entry of the beam element." + }, + "dphi": { + "displayName": "DPHI [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation around the x-axis." + }, + "dtheta": { + "displayName": "DTHETA [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation around the y-axis according to the right hand rule." + }, + "dpsi": { + "displayName": "DPSI [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation around the s-axis according to the right hand rule." + }, + "mrex": { + "displayName": "MREX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The horizontal read error for a monitor. This is ignored if the element is not a monitor." + }, + "mrey": { + "displayName": "MREY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The vertical read error for a monitor. This is ignored if the element is not a monitor." + }, + "mscalx": { + "displayName": "MSCALX", + "type": "RPNValue", + "defaultValue": 0, + "description": "The relative horizontal scaling error for a monitor. This is ignored if the element is not a monitor." + }, + "mscaly": { + "displayName": "MSCALY", + "type": "RPNValue", + "defaultValue": 0, + "description": "The relative vertical scaling error for a monitor. This is ignored if the element is not a monitor." + }, + "arex": { + "displayName": "AREX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The misalignment in the x-direction for the entry of an aperture limit." + }, + "arey": { + "displayName": "AREY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The misalignment in the y-direction for the entry of an aperture limit." + } + }, + "command_emit": { + "deltap": { + "displayName": "DELTAP", + "type": "RPNValue", + "defaultValue": 0, + "description": "The average energy error" + }, + "tol": { + "displayName": "TOL", + "type": "RPNValue", + "defaultValue": 1.000001, + "description": "The tolerance attribute is for the distinction between static and dynamic cases: if for the eigenvalues of the one-turn matrix, |e_val_5| SECTOR_NMUL and N <= SECTOR_NMUL_MAX are treated similar to SixTrack. If a negative value of SECTOR_NMUL_MAX is passed than it is also identified automatically. However, if multipolar parameters of the bends are to be modified inside the PTC universe, for example with PTC_READ_ERRORS, than this parameter needs to be set to a corresponding value. Please note that using large values (above 10) slows down the computations, so the smallest required value should be used." + }, + "sector_nmul_max": { + "displayName": "SECTOR_NMUL_MAX", + "type": "Integer", + "defaultValue": -1, + "description": "A global variable in PTC needed for exact sector bends defining up to which order Maxwell’s equation are solved. The value of SECTOR_NMUL_MAX must not be smaller than SECTOR_NMUL otherwise MAD-X stops with an error. If a negative value is passed than it is identified automatically by scanning the currently selected sequence." + }, + "symprint": { + "displayName": "SYMPRINT", + "type": "Boolean", + "defaultValue": "1", + "description": "A flag to enable the printing of the check of symplecticity. It is recommended to leave this flag set to TRUE." + } + }, + "command_ptc_end": {}, + "command_ptc_normal": { + "closed_orbit": { + "displayName": "CLOSED_ORBIT", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the closed orbit calculation." + }, + "deltap": { + "displayName": "DELTAP", + "type": "RPNValue", + "defaultValue": 0, + "description": "Relative momentum offset for reference closed orbit" + }, + "icase": { + "displayName": "ICASE", + "type": "Icase", + "defaultValue": "4", + "description": "Dimensionality of the phase-space (4, 5 or 6)" + }, + "map_table": { + "displayName": "MAP_TABLE", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the map-table in memory" + }, + "no": { + "displayName": "NO", + "type": "Integer", + "defaultValue": 1, + "description": "The order of the map." + }, + "normal": { + "displayName": "NORMAL", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the calculation of the Normal Form" + } + }, + "command_ptc_observe": { + "place": { + "displayName": "PLACE", + "type": "OptionalString", + "defaultValue": "", + "description": "The name of observation point." + } + }, + "command_ptc_select": { + "table": { + "displayName": "TABLE", + "type": "OptionalString", + "defaultValue": "", + "description": "The name of the table where values should be stored." + }, + "column": { + "displayName": "COLUMN", + "type": "OptionalString", + "defaultValue": "", + "description": "The name of the column in the table where values should be stored." + }, + "polynomial": { + "displayName": "POLYNOMIAL", + "type": "OptionalString", + "defaultValue": "", + "description": "Specifies the row of the map." + }, + "monomial": { + "displayName": "MONOMIAL", + "type": "OptionalString", + "defaultValue": "", + "description": "A string composed of digits that defines the monomials of the polynomial in PTC nomenclature. The length of the string should be equal to the number of variables and each digit corresponds to the exponent of the corresponding variable." + }, + "parametric": { + "displayName": "PARAMETRIC", + "type": "Boolean", + "defaultValue": "0", + "description": " If true, and if any knobs is defined, the map element is stored as the parametric result." + }, + "quantity": { + "displayName": "QUANTITY", + "type": "OptionalString", + "defaultValue": "" + } + }, + "command_ptc_setswitch": { + "debuglevel": { + "displayName": "DEBUGLEVEL", + "type": "Boolean", + "defaultValue": "1", + "description": "Sets the level of debugging printout: 0 prints none, 4 prints everything" + }, + "exact_mis": { + "displayName": "EXACT_MIS", + "type": "Boolean", + "defaultValue": "0", + "description": "Switch ensures exact misalignment treatment." + }, + "totalpath": { + "displayName": "TOTALPATH", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the 6th variable of PTC, i.e. 5th of MAD-X, is the total path. If false it is deviation from the reference particle, which is normally the closed orbit for closed layouts. This switch changes behaviour of the RF cavities, including RF multipoles and crab cavities." + }, + "radiation": { + "displayName": "ADIATION", + "type": "Boolean", + "defaultValue": "0", + "description": "Sets the radiation switch/internal state of PTC. In PTC basically all the elements radiate including sextupoles, solenoids and orbit correctors." + }, + "envelope": { + "displayName": "ENVELOPE", + "type": "Boolean", + "defaultValue": "0", + "description": "Sets the envelope switch/internal state of PTC. It allows to calculate dumping due to radiation and stochastic effects. Warning: this makes the tracking approximately twice slower, so low order should be used." + }, + "stochastic": { + "displayName": "STOCHASTIC", + "type": "Boolean", + "defaultValue": "0", + "description": "Sets the stochastic switch/internal state of PTC. It enables stochastic emission of photons in ray tracking, it only affects PTC_TRACK and PTC_TRACKLINE. The emission is calculated during map tracking therefore PTC_TWISS or PTC_NORMAL needs to be invoked before launching the tracking (also with RADIATION, ENVELOPE and STOCHASTIC set to true). Every tracked ray will receive the same stochastic kicks." + }, + "modulation": { + "displayName": "MODULATION", + "type": "Boolean", + "defaultValue": "0", + "description": "Sets the modulation switch/internal state of PTC. It needs to be set to true to observe effect of AD dipoles." + }, + "fringe": { + "displayName": "FRINGE", + "type": "Boolean", + "defaultValue": "0", + "description": "Sets the fringe switch/internal state of PTC." + } + }, + "command_ptc_start": { + "x": { + "displayName": "X", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $x$." + }, + "y": { + "displayName": "Y", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $y$." + }, + "px": { + "displayName": "PX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Horizontal canonical momentum of $px$." + }, + "py": { + "displayName": "PY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Horizontal canonical momentum of $py$." + }, + "t": { + "displayName": "T", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $t$" + }, + "pt": { + "displayName": "PT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $pt$" + }, + "fx": { + "displayName": "FX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Action-angle coordinate" + }, + "phix": { + "displayName": "PHIX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Action-angle coordinate" + }, + "fy": { + "displayName": "FY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Action-angle coordinate" + }, + "phiy": { + "displayName": "PHIY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Action-angle coordinate" + }, + "ft": { + "displayName": "FT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Action-angle coordinate" + }, + "phit": { + "displayName": "PHIT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Action-angle coordinate" + } + }, + "command_ptc_track": { + "beam_envelope": { + "displayName": "BEAM_ENVELOPE", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the calculations of the beam envelope with PTC" + }, + "closed_orbit": { + "displayName": "CLOSED_ORBIT", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the closed orbit calculation" + }, + "deltap": { + "displayName": "DELTAP", + "type": "RPNValue", + "defaultValue": 0, + "description": "Relative momentum offset for reference closed orbit (used for 5D case ONLY)" + }, + "element_by_element": { + "displayName": "ELEMENT_BY_ELEMENT", + "type": "Boolean", + "defaultValue": "0", + "description": "Switch from the default turn-by-turn tracking to the element-by-element tracking" + }, + "file": { + "displayName": "FILE", + "type": "OutputFile", + "defaultValue": "", + "description": "The name of the file output will be written to" + }, + "ffile": { + "displayName": "FFILE", + "type": "Integer", + "defaultValue": 1, + "description": "Printing coordinates after every FFILE turns" + }, + "icase": { + "displayName": "ICASE", + "type": "Icase", + "defaultValue": "4", + "description": "User-defined dimensionality of the phase-space (4, 5 or 6)" + }, + "maxaper": { + "displayName": "MAXAPER", + "type": "Float6StringArray", + "defaultValue": "0, 0, 0, 0, 0, 0", + "description": "Upper limits for the particle coordinates" + }, + "norm_no": { + "displayName": "NORM_NO", + "type": "Integer", + "defaultValue": 1, + "description": "Order of the Normal Form" + }, + "norm_out": { + "displayName": "NORM_OUT", + "type": "Boolean", + "defaultValue": "0", + "description": "Transform canonical variables to action-angle variables" + }, + "radiation": { + "displayName": "RADIATION", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the synchrotron radiation calculated by an internal procedure of PTC" + }, + "radiation_energy_loss": { + "displayName": "RADIATION_ENERGY_LOSS", + "type": "Boolean", + "defaultValue": "0", + "description": "Adds the energy loss for radiation_model1" + }, + "radiation_model1": { + "displayName": "RADIATION_MODEL1", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the radiation according to the method given in the Ref" + }, + "radiation_quad": { + "displayName": "RADIATION_QUAD", + "type": "Boolean", + "defaultValue": "0", + "description": "Adds the radiation in quadrupoles" + }, + "recloss": { + "displayName": "RECLOSS", + "type": "Boolean", + "defaultValue": "0", + "description": "Create in memory a table named ”trackloss” containing the coordinates of lost particles. " + }, + "space_charge": { + "displayName": "SPACE_CHARGE", + "type": "Boolean", + "defaultValue": "0", + "description": "Turn on the simulations of the space charge forces between particles" + }, + "turns": { + "displayName": "TURNS", + "type": "Integer", + "defaultValue": 0, + "description": "Number of turns to be tracked" + }, + "onetable": { + "displayName": "ONETABLE", + "type": "Boolean", + "defaultValue": "0" + } + }, + "command_ptc_track_end": {}, + "command_ptc_trackline": { + "turns": { + "displayName": "TURNS", + "type": "RPNValue", + "defaultValue": 1, + "description": "Number of turns to be tracked. If the layout of the machine is not closed, this value is forced to TURNS=1 by PTC" + }, + "file": { + "displayName": "FILE", + "type": "OutputFile", + "defaultValue": "" + }, + "everystep": { + "displayName": "EVERYSTEP", + "type": "Boolean", + "defaultValue": "0", + "description": "a logical switch to activate the recording of track parameters at every integration step. Normally tracking data are stored internally only at the end of each element. EVERYSTEP provides the user with finer data points. It implies usage of the so called node (thin) layout." + }, + "gcs": { + "displayName": "GCS", + "type": "Boolean", + "defaultValue": "0", + "description": "A logical switch to store track parameters in Global Coordinate System - normally it starts at the entrance face of the first element." + }, + "onetable": { + "displayName": "ONETABLE", + "type": "Boolean", + "defaultValue": "0" + } + }, + "command_ptc_twiss": { + "alfx": { + "displayName": "ALFX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Correlation function $\\alpha_x$" + }, + "alfy": { + "displayName": "ALFY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Correlation function $\\alpha_y$" + }, + "alfz": { + "displayName": "ALFz", + "type": "RPNValue", + "defaultValue": 0, + "description": "Correlation function $\\alpha_z$" + }, + "beta0": { + "displayName": "BETA0", + "type": "OptionalString", + "defaultValue": "", + "description": "The name of a BETA0 block containing the Twiss parameters to be used as input" + }, + "betx": { + "displayName": "BETX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Amplitude function $\\beta_x$" + }, + "bety": { + "displayName": "BETY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Amplitude function $\\beta_y$" + }, + "betz": { + "displayName": "BETZ [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Amplitude function $\\beta_z$" + }, + "closed_orbit": { + "displayName": "CLOSED ORBIT", + "type": "Boolean", + "defaultValue": "0", + "description": "trigger the closed orbit calculation (applies to periodic solution ONLY)" + }, + "deltap": { + "displayName": "DELTAP", + "type": "RPNValue", + "defaultValue": 0, + "description": "relative momentum offset for reference closed orbit" + }, + "deltap_dependency": { + "displayName": "DELTAP DEPENDENCY", + "type": "Boolean", + "defaultValue": "0", + "description": "trigger the computation of the Twiss and dispersion derivatives." + }, + "dpx": { + "displayName": "DPX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $p_x$: $D_{px}$" + }, + "dpy": { + "displayName": "DPY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $p_y$: $D_{py}$" + }, + "dx": { + "displayName": "DX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $x$" + }, + "dy": { + "displayName": "DY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $y$" + }, + "file": { + "displayName": "FILE", + "type": "OutputFile", + "defaultValue": "", + "description": "The name of the file TWISS output will be written to" + }, + "icase": { + "displayName": "ICASE", + "type": "Icase", + "defaultValue": "4", + "description": "the dimensionality of the phase-space (4, 5 or 6)" + }, + "ignore_map_orbit": { + "displayName": "IGNORE MAP ORBIT", + "type": "Boolean", + "defaultValue": "0", + "description": "ignore the orbit in the map and use the closed orbit instead if requested, or the orbit defined by the starting point specified with X, PX, Y, P, T, DT parameters otherwise." + }, + "initial_map_manual": { + "displayName": "INITIAL MAP MANUAL", + "type": "Boolean", + "defaultValue": "0", + "description": "trigger the use of an input map stored beforehand in file ”fort.18”, e.g. by a previous initial run of PTC_NORMAL)." + }, + "initial_matrix_manual": { + "displayName": "INITIAL MATRIX MANUAL", + "type": "Boolean", + "defaultValue": "0", + "description": "trigger the use of the input variables RE11, ...,RE66 as the transfer matrix." + }, + "mux": { + "displayName": "MUX [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Phase function of $\\mu_y$." + }, + "muy": { + "displayName": "MUY [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Phase function of $\\mu_y$." + }, + "normal": { + "displayName": "NORMAL", + "type": "Boolean", + "defaultValue": "0", + "description": "saving of the normal form analysis results (the closed solution) into dedicated table called NONLIN. It is the same as ptc_normal. However, the nonlin table has format such that its coefficients can be accessed within the MADX script using table command. This permits, for example, to perform matching of these parameters or or value extraction to a variable. Also, all available orders are calculated and no select_ptc_normal is required. Currently the following parameters are calculated: tunes (and all their derivatives), dipsersions (and all their derivatives), eigen values, transfer map, resonance driving terms (generating function) and the pseudo Hamiltonian. If radiation and envelope is switched on with PTC_SETSWITCH then damping decrements, equilibrium emittances and beam sizes are calculated. Attention: the results are always the plain polynomial coefficients, which is different from ptc_normal nomenclature for some variables, which in turn always gives values of the partial derivatives. Therefore, in order to obtain values of the partial derivatives the respective factorials and binomial coefficients need to be factored out by the user." + }, + "pt": { + "displayName": "PT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Energy difference, divided by the reference momentum times the velocity of light." + }, + "px": { + "displayName": "PX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Horizontal canonical momentum of $p_x$" + }, + "py": { + "displayName": "PY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Vertical canonical momentum of $p_y$" + }, + "range": { + "displayName": "RANGE", + "type": "OptionalString", + "defaultValue": "", + "description": "The TWISS calculation is restricted to the specified range." + }, + "re11": { + "displayName": "RE11", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re12": { + "displayName": "RE12", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re13": { + "displayName": "RE13", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re14": { + "displayName": "RE14", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re15": { + "displayName": "RE15", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re16": { + "displayName": "RE16", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re21": { + "displayName": "RE21", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re22": { + "displayName": "RE22", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re23": { + "displayName": "RE23", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re24": { + "displayName": "RE24", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re25": { + "displayName": "RE25", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re26": { + "displayName": "RE26", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re31": { + "displayName": "RE31", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re32": { + "displayName": "RE32", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re33": { + "displayName": "RE33", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re34": { + "displayName": "RE34", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re35": { + "displayName": "RE35", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re36": { + "displayName": "RE36", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re41": { + "displayName": "RE41", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re42": { + "displayName": "RE42", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re43": { + "displayName": "RE43", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re44": { + "displayName": "RE44", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re45": { + "displayName": "RE45", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re46": { + "displayName": "RE46", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re51": { + "displayName": "RE51", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re52": { + "displayName": "RE52", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re53": { + "displayName": "RE53", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re54": { + "displayName": "RE54", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re55": { + "displayName": "RE55", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re56": { + "displayName": "RE56", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re61": { + "displayName": "RE61", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re62": { + "displayName": "RE62", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re63": { + "displayName": "RE63", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re64": { + "displayName": "RE64", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re65": { + "displayName": "RE65", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re66": { + "displayName": "RE66", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "ring_parameters": { + "displayName": "RING PARAMETERS", + "type": "Boolean", + "defaultValue": "0", + "description": "force computation of ring parameters" + }, + "slice_magnets": { + "displayName": "SLICE MAGNETS", + "type": "Boolean", + "defaultValue": "0", + "description": "activate the evaluation of Twiss parameters at each integration step inside magnets, in addition to the end face. The number of slices is determined by the number of steps (NST) that can be separately defined for each element, or otherwise set by NST parameter when creating the PTC layout. Note that the orbit rms calculated in this mode counts as valid data points both the end of the previous element and the entrance of the current element. Since the first integration node is always at the entrance of the magnet (after position offset and fringe effects are calculated) which corresponds to the same s position (and usually optical functions) as the end of the previous element, the points at the interface between magnets are included twice in the rms calculation." + }, + "t": { + "displayName": "T [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Velocity of light times the negative time difference with respect to the reference particle. A positive T means that the particle arrives ahead of the reference particle." + }, + "trackrdts": { + "displayName": "TRACKRDTS", + "type": "Boolean", + "defaultValue": "0", + "description": "tracking of Resonance Driving Terms (RDTs). For each element all RDTs from order 3 up to value defined by switch NO are saved in TWISSRDT table. This table contains also auxiliary columns as s position, element names, strengths and lengths such that RDT values can be plotted the same way as values from TWISS table. RDTs are elements of the generating function (GFN) of the normalization transformation and for compatibility with PTC_NORMAL notation the columns are prefixed with GNF. Because they are complex numbers 3 values are saved: real part (GNFC), imaginary part (GNFS) and amplitude (GNFA)." + }, + "x": { + "displayName": "X", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $x$" + }, + "y": { + "displayName": "Y", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $y$" + } + }, + "command_resbeam": { + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "" + } + }, + "command_savebeta": { + "label": { + "displayName": "LABEL", + "type": "OptionalString", + "defaultValue": "", + "description": "Name of the label." + }, + "place": { + "displayName": "PLACE", + "type": "OptionalString", + "defaultValue": "", + "description": "The location of the mark." + }, + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Name of the expaned sequence." + } + }, + "command_select": { + "class": { + "displayName": "CLASS", + "type": "OptionalString", + "defaultValue": "", + "description": "The class of elements to be selected." + }, + "clear": { + "displayName": "CLEAR", + "type": "Boolean", + "defaultValue": "0", + "description": "Deselects ALL positions in the sequence for the flag ”name”." + }, + "column": { + "displayName": "COLUMN", + "type": "OptionalString", + "defaultValue": "", + "description": "The name of the column." + }, + "flag": { + "displayName": "FLAG", + "type": "OptionalString", + "defaultValue": "", + "description": "Determines the applicability of the SELECT statement." + }, + "full": { + "displayName": "FULL", + "type": "Boolean", + "defaultValue": "0", + "description": "The default for the MAKETHIN flag and for tables" + }, + "pattern": { + "displayName": "PATTERN", + "type": "OptionalString", + "defaultValue": "", + "description": "The regular expression pattern for the element names to be selected." + }, + "range": { + "displayName": "RANGE", + "type": "OptionalString", + "defaultValue": "", + "description": "The range of elements to be selected." + }, + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "The name of a sequence to which the selection is applied." + }, + "slice": { + "displayName": "SLICE", + "type": "Integer", + "defaultValue": 1, + "description": "The number of slices into which the selected elements have to be cut. Only used by MAKETHIN and FLAG=INTERPOLATE" + }, + "thick": { + "displayName": "THICK", + "type": "Boolean", + "defaultValue": "0", + "description": "Indicate whether the selected elements are treated as thick elements by the MAKETHIN command. " + } + }, + "command_set": { + "format": { + "displayName": "FORMAT", + "type": "OptionalString", + "defaultValue": "", + "description": "Format output. Must double-quote each format." + }, + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Select the sequence" + } + }, + "command_show": { + "command": { + "displayName": "COMMAND", + "type": "String", + "defaultValue": "", + "description": "Print the command with the values of all its parameters." + } + }, + "command_sodd": { + "detune": { + "displayName": "DETUNE", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the detune subroutine is executed" + }, + "distort1": { + "displayName": "DISTORT1", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the distort1 subroutine is executed" + }, + "distort2": { + "displayName": "DISTORT2", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the distort2 subroutine is executed" + }, + "multipole_order_range": { + "displayName": "MULTIPOLE_ORDER_RANGE", + "type": "Integer2StringArray", + "defaultValue": "0, 0", + "description": "Longitudinal interval of the beam line (in m)", + "min": "start, stop" + }, + "noprint ": { + "displayName": "NOPRINT", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, no file or internal table will be created to keep the results" + }, + "nosixtrack": { + "displayName": "NOSIXTRACK", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the input file fc.34 will not be generated internally by invoking the conversion routine of sixtrack and the user should provide it before the execution of the sodd command" + }, + "print_all": { + "displayName": "PRINT_ALL", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the files and internal tables containing results at each multipole will be generated" + }, + "print_at_end": { + "displayName": "PRINT_AT_END", + "type": "Boolean", + "defaultValue": "0", + "description": "If true, the files and internal tables containing results at the end of the position range will be generated" + }, + "start_stop": { + "displayName": "START_STOP", + "type": "Float2StringArray", + "defaultValue": "0, 0", + "description": "Longitudinal interval of the beam line (in m)", + "min": "start, stop" + } + }, + "command_touschek": { + "tolerance": { + "displayName": "TOLERANCE", + "type": "RPNValue", + "defaultValue": 1e-7, + "description": "the tolerance for the numerical integrator DGAUSS" + }, + "file": { + "displayName": "FILE", + "type": "OutputFile", + "defaultValue": "", + "description": "The name of the output file" + } + }, + "command_twiss": { + "alfx": { + "displayName": "ALFX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Correlation function $\\alpha_x$" + }, + "alfy": { + "displayName": "ALFY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Correlation function $\\alpha_y$" + }, + "beta0": { + "displayName": "BETA0", + "type": "OptionalString", + "defaultValue": "", + "description": "The name of a BETA0 block containing the Twiss parameters to be used as input" + }, + "betx": { + "displayName": "BETX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Amplitude function $\\beta_x$" + }, + "bety": { + "displayName": "BETY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Amplitude function $\\beta_y$" + }, + "centre": { + "displayName": "CENTRE", + "type": "Boolean", + "defaultValue": "0", + "description": "Enforce the calculation of the linear lattice functions at the center of the element instead of the end of the element." + }, + "chrom": { + "displayName": "CHROM", + "type": "Boolean", + "defaultValue": "0", + "description": "A logical flag to trigger computation of the chromatic functions as well as the radiation synchrotron integrals." + }, + "ddpx": { + "displayName": "DDPX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic derivative of dispersion $D_{px}$" + }, + "ddpy": { + "displayName": "DDPY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic derivative of dispersion $D_{py}$" + }, + "ddx": { + "displayName": "DDX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic derivative of dispersion $D_x$" + }, + "ddy": { + "displayName": "DDY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic derivative of dispersion $D_y$" + }, + "deltap": { + "displayName": "DELTAP", + "type": "RPNValue", + "defaultValue": 0, + "description": "Difference between the reference momentum and the design momentum, divided by the design momentum." + }, + "dmux": { + "displayName": "DMUX [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic derivative of phase function $\\mu_x$" + }, + "dmuy": { + "displayName": "DMUY [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic derivative of phase function $\\mu_x$" + }, + "dpx": { + "displayName": "DPX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $p_x$: $D_{px}$" + }, + "dpy": { + "displayName": "DPY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $p_y$: $D_{py}$" + }, + "dx": { + "displayName": "DX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $x$" + }, + "dy": { + "displayName": "DY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Dispersion of $y$" + }, + "energy": { + "displayName": "ENERGY [GeV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The total energy per particle." + }, + "file": { + "displayName": "FILE", + "type": "OutputFile", + "defaultValue": "", + "description": "The name of the file TWISS output will be written to" + }, + "keeporbit": { + "displayName": "KEEPORBIT", + "type": "OptionalString", + "defaultValue": "", + "description": "Store the orbit under this name at the start, and at all monitors." + }, + "line": { + "displayName": "LINE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Name of a valid beamline for which the calculation of optical functions should be performed. " + }, + "mux": { + "displayName": "MUX [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Phase function of $\\mu_y$." + }, + "muy": { + "displayName": "MUY [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Phase function of $\\mu_y$." + }, + "phix": { + "displayName": "PHIX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic phase function $\\phi_x$" + }, + "phiy": { + "displayName": "PHIY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Chromatic phase function $\\phi_x$" + }, + "pt": { + "displayName": "PT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Energy difference, divided by the reference momentum times the velocity of light." + }, + "px": { + "displayName": "PX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Horizontal canonical momentum of $p_x$" + }, + "py": { + "displayName": "PY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Vertical canonical momentum of $p_y$" + }, + "r11": { + "displayName": "R11", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "r12": { + "displayName": "R12", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "r21": { + "displayName": "R21", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "r22": { + "displayName": "R22", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "range": { + "displayName": "RANGE", + "type": "OptionalString", + "defaultValue": "", + "description": "The TWISS calculation is restricted to the specified range." + }, + "re11": { + "displayName": "RE11", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re12": { + "displayName": "RE12", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re13": { + "displayName": "RE13", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re14": { + "displayName": "RE14", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re15": { + "displayName": "RE15", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re16": { + "displayName": "RE16", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re21": { + "displayName": "RE21", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re22": { + "displayName": "RE22", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re23": { + "displayName": "RE23", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re24": { + "displayName": "RE24", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re25": { + "displayName": "RE25", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re26": { + "displayName": "RE26", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re31": { + "displayName": "RE31", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re32": { + "displayName": "RE32", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re33": { + "displayName": "RE33", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re34": { + "displayName": "RE34", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re35": { + "displayName": "RE35", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re36": { + "displayName": "RE36", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re41": { + "displayName": "RE41", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re42": { + "displayName": "RE42", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re43": { + "displayName": "RE43", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re44": { + "displayName": "RE44", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re45": { + "displayName": "RE45", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re46": { + "displayName": "RE46", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re51": { + "displayName": "RE51", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re52": { + "displayName": "RE52", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re53": { + "displayName": "RE53", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re54": { + "displayName": "RE54", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re55": { + "displayName": "RE55", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "re56": { + "displayName": "RE56", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re61": { + "displayName": "RE61", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re62": { + "displayName": "RE62", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re63": { + "displayName": "RE63", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re64": { + "displayName": "RE64", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re65": { + "displayName": "RE65", + "type": "RPNValue", + "defaultValue": 0, + "description": "Coupling matrix" + }, + "re66": { + "displayName": "RE66", + "type": "RPNValue", + "defaultValue": 1, + "description": "Coupling matrix" + }, + "ripken": { + "displayName": "RIPKEN", + "type": "Boolean", + "defaultValue": "0", + "description": "Calculate the Ripken-Mais Twiss parameters." + }, + "rmatrix": { + "displayName": "RMATRIX", + "type": "Boolean", + "defaultValue": "0", + "description": "If this flag is used the the one-turn map at the location of every element is calculated and prepared for storage in the twiss table." + }, + "sectoracc": { + "displayName": "SECTORACC", + "type": "Boolean", + "defaultValue": "0", + "description": "Save composition of maps instead of individual maps of a sector map." + }, + "sectorfile": { + "displayName": "SECTORFILE", + "type": "OutputFile", + "defaultValue": "0", + "description": "Name of the file to which the SECTORMAP is written." + }, + "sectormap": { + "displayName": "SECTORMAP", + "type": "Boolean", + "defaultValue": "0", + "description": "Initiate the calculation of a sector map." + }, + "sectorpure": { + "displayName": "SECTORPURE", + "type": "Boolean", + "defaultValue": "0", + "description": "Save the transfer map Rij without effects from higher order map (Tijk)." + }, + "sectortable": { + "displayName": "SECTORTABLE", + "type": "OptionalString", + "defaultValue": "", + "description": "Name of the table containing the SECTORMAP values." + }, + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Name of a valid sequence for which the calculation of optical functions should be performed. " + }, + "t": { + "displayName": "T [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Velocity of light times the negative time difference with respect to the reference particle. A positive T means that the particle arrives ahead of the reference particle." + }, + "tolerance": { + "displayName": "TOLERANCE", + "type": "RPNValue", + "defaultValue": 0.000001, + "description": "The maximum closed orbit error, for all six orbit components, that can be tolerated during the closed orbit search. The value given in the TWISS command is only valid for the current calculation; the COGUESS command allows to change the default value for all subsequent closed orbit search calculations." + }, + "useorbit": { + "displayName": "USEORBIT", + "type": "OptionalString", + "defaultValue": "", + "description": "Use the start value provided for the closed orbit search." + }, + "wx": { + "displayName": "WX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The horizontal Courant-Snyder invariant " + }, + "wy": { + "displayName": "WY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The vertical Courant-Snyder invariant " + }, + "x": { + "displayName": "X", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $x$" + }, + "y": { + "displayName": "Y", + "type": "RPNValue", + "defaultValue": 0, + "description": "Canonical coordinate $y$" + } + }, + "command_use": { + "sequence": { + "displayName": "SEQUENCE", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Name of the sequence to be loaded and expanded." + }, + "period": { + "displayName": "PERIOD", + "type": "OptionalLatticeBeamlineList", + "defaultValue": "", + "description": "Name of the sequence to be loaded and expanded." + } + }, + "command_vary": { + "name": { + "displayName": "NAME", + "type": "OptionalString", + "defaultValue": "", + "description": "Name of the parameter or attribute to be varied" + }, + "step": { + "displayName": "STEP", + "type": "RPNValue", + "defaultValue": 0, + "description": "Approximate initial step size for varying the parameter" + }, + "lower": { + "displayName": "LOWER", + "type": "RPNValue", + "defaultValue": 0, + "description": "Lower limit for the parameter" + }, + "upper": { + "displayName": "UPPER", + "type": "RPNValue", + "defaultValue": 0, + "description": "Upper limit for the parameter" + }, + "slope": { + "displayName": "SLOPE", + "type": "CommandVarySlope", + "defaultValue": "-none-", + "description": "Upper limit for the parameter" + }, + "opt": { + "displayName": "OPT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Optimal value for the parameter" + } + }, + "elementAnimation": { + "x": { + "displayName": "Horizontal Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "y1": { + "displayName": "Vertical Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "y2": { + "displayName": "Vertical Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "y3": { + "displayName": "Vertical Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "includeLattice": { + "displayName": "Show Lattice Overlay", + "type": "Boolean", + "defaultValue": "0" + }, + "histogramBins": { + "displayName": "Histogram Bins", + "type": "Integer", + "defaultValue": 200 + }, + "framesPerSecond": { + "displayName": "Frames per Second", + "type": "FramesPerSecond", + "defaultValue": "2" + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "afmhot" + }, + "plotRangeType": { + "displayName": "Range", + "type": "PlotRangeType", + "defaultValue": "none" + }, + "horizontalSize": { + "displayName": "Horizontal Size", + "type": "Float", + "defaultValue": 0 + }, + "verticalSize": { + "displayName": "Vertical Size", + "type": "Float", + "defaultValue": 0 + }, + "horizontalOffset": { + "displayName": "Horizontal Offset", + "type": "Float", + "defaultValue": 0 + }, + "verticalOffset": { + "displayName": "Vertical Offset", + "type": "Float", + "defaultValue": 0 + }, + "aspectRatio": { + "displayName": "Aspect Ratio", + "type": "AspectRatio", + "defaultValue": "1" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "matchSummaryAnimation": {}, + "rpnVariable": { + "name": { + "displayName": "Name", + "type": "String" + }, + "value": { + "displayName": "Value", + "type": "RPNValue" + } + }, + "twissEllipseReport": { + "dim": { + "displayName": "Dimension", + "type": "SpaceCoordinate", + "defaultValue": "x" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "twissFromParticlesAnimation": { + "x": { + "displayName": "Horizontal Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "y1": { + "displayName": "Vertical Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "y2": { + "displayName": "Vertical Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "y3": { + "displayName": "Vertical Value to Plot", + "type": "ValueList", + "defaultValue": "" + }, + "includeLattice": { + "displayName": "Show Lattice Overlay", + "type": "Boolean", + "defaultValue": "1" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "twissReport": { + "y1": { + "displayName": "Y1 Value", + "type": "TwissParameter", + "defaultValue": "betx" + }, + "y2": { + "displayName": "Y2 Value", + "type": "TwissParameter", + "defaultValue": "bety" + }, + "y3": { + "displayName": "Y3 Value", + "type": "TwissParameter", + "defaultValue": "dx" + }, + "includeLattice": { + "displayName": "Show Lattice Overlay", + "type": "Boolean", + "defaultValue": "1" + } + }, + "BEAMBEAM": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "sigx": { + "displayName": "SIGX [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The horizontal extent of the opposite beam." + }, + "sigy": { + "displayName": "SIGY [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The vertical extent of the opposite beam." + }, + "xma": { + "displayName": "XMA [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The horizontal displacement of the opposite beam with respect to the ideal orbit." + }, + "yma": { + "displayName": "YMA [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The vertical displacement of the opposite beam with respect to the ideal orbit." + }, + "charge": { + "displayName": "CHARGE", + "type": "RPNValue", + "defaultValue": 1, + "description": "The charge of particles in the opposite beam in elementary charges." + }, + "bbshape": { + "displayName": "BBSHAPE", + "type": "BeambeamBbshape", + "defaultValue": "1", + "description": "The parameter to choose the radial density shape of the opposite beam." + }, + "width": { + "displayName": "WIDTH [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The relative extent of the edge region." + }, + "bbdir": { + "displayName": "BBDIR", + "type": "BeambeamBbdir", + "defaultValue": "-1", + "description": "The direction of motion of the opposite beam relative to the beam considered." + } + }, + "CHANGEREF": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "patch_ang": { + "displayName": "PATCH_ANG", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "patch_trans": { + "displayName": "PATCH_TRANS", + "type": "FloatArray", + "defaultValue": "0 0 0" + } + }, + "COLLIMATOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The collimator length" + } + }, + "CRABCAVITY": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the cavity" + }, + "volt": { + "displayName": "VOLT [MV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The peak RF voltage" + }, + "lag": { + "displayName": "LAG [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The initial phase lag." + }, + "freq": { + "displayName": "FREQ [MHz]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The frequency." + }, + "rv1": { + "displayName": "RV1", + "type": "Integer", + "defaultValue": 0, + "description": "Number of initial turns with zero voltage." + }, + "rv2": { + "displayName": "RV2", + "type": "Integer", + "defaultValue": 0, + "description": "Number of turns to ramp voltage from zero to nominal." + }, + "rv3": { + "displayName": "RV3", + "type": "Integer", + "defaultValue": 0, + "description": "Number of turns with nominal voltage." + }, + "rv4": { + "displayName": "RV4", + "type": "Integer", + "defaultValue": 0, + "description": "Number of turns to ramp voltage from nominal to zero." + }, + "rph1": { + "displayName": "RPH1", + "type": "Integer", + "defaultValue": 0, + "description": "Number of initial turns with nominal phase." + }, + "rph2": { + "displayName": "RPH2 [2$\\pi$]", + "type": "Integer", + "defaultValue": 0, + "description": "Number of turns to ramp phase [2$\\pi$] from nominal to specified value." + }, + "lagf": { + "displayName": "LAGF [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Value of the final crab RF phase lag" + } + }, + "DIPEDGE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "h": { + "displayName": "H [$\\bf m^{-2}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Is angle/length or 1/$\\rho$" + }, + "e1": { + "displayName": "E1 [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle for the pole face." + }, + "fint": { + "displayName": "FINT", + "type": "RPNValue", + "defaultValue": 0, + "description": "Field integral as for SBEND" + }, + "hgap": { + "displayName": "HGAP [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Half gap height of the associated SBEND" + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "DRIFT": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the drift." + } + }, + "ECOLLIMATOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L", + "type": "RPNValue [m]", + "defaultValue": 0, + "description": "The collimator length." + }, + "xsize": { + "displayName": "XSIZE", + "type": "RPNValue", + "defaultValue": 0, + "description": "*OBSOLETE*The horizontal half-aperture." + }, + "ysize": { + "displayName": "YSIZE", + "type": "RPNValue", + "defaultValue": 0, + "description": "*OBSOLETE* The vertical half-aperture." + } + }, + "ELSEPARATOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the separator" + }, + "ex": { + "displayName": "EX [Mv/m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The horizontal electric field strengt" + }, + "ey": { + "displayName": "EY [Mv/m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The vertical electric field strength." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "HACDIPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the device." + }, + "volt": { + "displayName": "VOLT [MV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The amplitude of the kick." + }, + "freq": { + "displayName": "FREQ [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Tune of the oscillation." + }, + "lag": { + "displayName": "LAG [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The phase lag." + }, + "ramp1": { + "displayName": "RAMP1", + "type": "Integer", + "defaultValue": 0, + "description": "Starting turn of amplitude ramp-up." + }, + "ramp2": { + "displayName": "RAMP2", + "type": "Integer", + "defaultValue": 0, + "description": "Last turn of amplitude ramp-up." + }, + "ramp3": { + "displayName": "RAMP3", + "type": "Integer", + "defaultValue": 0, + "description": "Starting turn of amplitude ramp-down. " + }, + "ramp4": { + "displayName": "RAMP4", + "type": "Integer", + "defaultValue": 0, + "description": "Last turn of amplitude ramp-down." + } + }, + "HKICKER": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the closed orbit corrector." + }, + "kick": { + "displayName": "KICK", + "type": "RPNValue", + "defaultValue": 0, + "description": "The momentum change $\\delta PX$" + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "HMONITOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the monitor." + } + }, + "INSTRUMENT": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the instrument." + } + }, + "KICKER": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the closed orbit corrector." + }, + "hkick": { + "displayName": "HKICK", + "type": "RPNValue", + "defaultValue": 0, + "description": "The horizontal momentum change $\\delta PX$" + }, + "vkick": { + "displayName": "VKICK", + "type": "RPNValue", + "defaultValue": 0, + "description": "The vertical momentum change $\\delta PY$" + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "MARKER": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + } + }, + "MATRIX": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "Length of the element." + }, + "kick1": { + "displayName": "KICK1", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the kick of the element acting on the six phase space coordinates." + }, + "kick6": { + "displayName": "KICK6", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the kick of the element acting on the six phase space coordinates." + }, + "rm11": { + "displayName": "RM11", + "type": "RPNValue", + "defaultValue": 1, + "description": "Defines the linear transfer matrix of the element." + }, + "rm66": { + "displayName": "RM66", + "type": "RPNValue", + "defaultValue": 1, + "description": "Defines the linear transfer matrix of the element." + }, + "tm111": { + "displayName": "TM111", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm666": { + "displayName": "TM666", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "kick2": { + "displayName": "KICK2", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the kick of the element acting on the six phase space coordinates." + }, + "kick3": { + "displayName": "KICK3", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the kick of the element acting on the six phase space coordinates." + }, + "kick4": { + "displayName": "KICK4", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the kick of the element acting on the six phase space coordinates." + }, + "kick5": { + "displayName": "KICK5", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the kick of the element acting on the six phase space coordinates." + }, + "rm12": { + "displayName": "RM12", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm13": { + "displayName": "RM13", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm14": { + "displayName": "RM14", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm15": { + "displayName": "RM15", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm16": { + "displayName": "RM16", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm21": { + "displayName": "RM21", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm22": { + "displayName": "RM22", + "type": "RPNValue", + "defaultValue": 1, + "description": "Defines the linear transfer matrix of the element." + }, + "rm23": { + "displayName": "RM23", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm24": { + "displayName": "RM24", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm25": { + "displayName": "RM25", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm26": { + "displayName": "RM26", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm31": { + "displayName": "RM31", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm32": { + "displayName": "RM32", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm33": { + "displayName": "RM33", + "type": "RPNValue", + "defaultValue": 1, + "description": "Defines the linear transfer matrix of the element." + }, + "rm34": { + "displayName": "RM34", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm35": { + "displayName": "RM35", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm36": { + "displayName": "RM36", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm41": { + "displayName": "RM41", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm42": { + "displayName": "RM42", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm43": { + "displayName": "RM43", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm44": { + "displayName": "RM44", + "type": "RPNValue", + "defaultValue": 1, + "description": "Defines the linear transfer matrix of the element." + }, + "rm45": { + "displayName": "RM45", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm46": { + "displayName": "RM46", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm51": { + "displayName": "RM51", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm52": { + "displayName": "RM52", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm53": { + "displayName": "RM53", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm54": { + "displayName": "RM54", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm55": { + "displayName": "RM55", + "type": "RPNValue", + "defaultValue": 1, + "description": "Defines the linear transfer matrix of the element." + }, + "rm56": { + "displayName": "RM56", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm61": { + "displayName": "RM61", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm62": { + "displayName": "RM62", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm63": { + "displayName": "RM63", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm64": { + "displayName": "RM64", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "rm65": { + "displayName": "RM65", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the linear transfer matrix of the element." + }, + "tm112": { + "displayName": "TM112", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm113": { + "displayName": "TM113", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm114": { + "displayName": "TM114", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm115": { + "displayName": "TM115", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm116": { + "displayName": "TM116", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm121": { + "displayName": "TM121", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm122": { + "displayName": "TM122", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm123": { + "displayName": "TM123", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm124": { + "displayName": "TM124", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm125": { + "displayName": "TM125", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm126": { + "displayName": "TM126", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm131": { + "displayName": "TM131", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm132": { + "displayName": "TM132", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm133": { + "displayName": "TM133", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm134": { + "displayName": "TM134", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm135": { + "displayName": "TM135", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm136": { + "displayName": "TM136", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm141": { + "displayName": "TM141", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm142": { + "displayName": "TM142", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm143": { + "displayName": "TM143", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm144": { + "displayName": "TM144", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm145": { + "displayName": "TM145", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm146": { + "displayName": "TM146", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm151": { + "displayName": "TM151", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm152": { + "displayName": "TM152", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm153": { + "displayName": "TM153", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm154": { + "displayName": "TM154", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm155": { + "displayName": "TM155", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm156": { + "displayName": "TM156", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm161": { + "displayName": "TM161", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm162": { + "displayName": "TM162", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm163": { + "displayName": "TM163", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm164": { + "displayName": "TM164", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm165": { + "displayName": "TM165", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm166": { + "displayName": "TM166", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm211": { + "displayName": "TM211", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm212": { + "displayName": "TM212", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm213": { + "displayName": "TM213", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm214": { + "displayName": "TM214", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm215": { + "displayName": "TM215", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm216": { + "displayName": "TM216", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm221": { + "displayName": "TM221", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm222": { + "displayName": "TM222", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm223": { + "displayName": "TM223", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm224": { + "displayName": "TM224", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm225": { + "displayName": "TM225", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm226": { + "displayName": "TM226", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm231": { + "displayName": "TM231", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm232": { + "displayName": "TM232", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm233": { + "displayName": "TM233", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm234": { + "displayName": "TM234", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm235": { + "displayName": "TM235", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm236": { + "displayName": "TM236", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm241": { + "displayName": "TM241", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm242": { + "displayName": "TM242", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm243": { + "displayName": "TM243", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm244": { + "displayName": "TM244", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm245": { + "displayName": "TM245", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm246": { + "displayName": "TM246", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm251": { + "displayName": "TM251", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm252": { + "displayName": "TM252", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm253": { + "displayName": "TM253", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm254": { + "displayName": "TM254", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm255": { + "displayName": "TM255", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm256": { + "displayName": "TM256", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm261": { + "displayName": "TM261", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm262": { + "displayName": "TM262", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm263": { + "displayName": "TM263", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm264": { + "displayName": "TM264", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm265": { + "displayName": "TM265", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm266": { + "displayName": "TM266", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm311": { + "displayName": "TM311", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm312": { + "displayName": "TM312", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm313": { + "displayName": "TM313", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm314": { + "displayName": "TM314", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm315": { + "displayName": "TM315", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm316": { + "displayName": "TM316", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm321": { + "displayName": "TM321", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm322": { + "displayName": "TM322", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm323": { + "displayName": "TM323", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm324": { + "displayName": "TM324", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm325": { + "displayName": "TM325", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm326": { + "displayName": "TM326", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm331": { + "displayName": "TM331", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm332": { + "displayName": "TM332", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm333": { + "displayName": "TM333", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm334": { + "displayName": "TM334", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm335": { + "displayName": "TM335", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm336": { + "displayName": "TM336", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm341": { + "displayName": "TM341", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm342": { + "displayName": "TM342", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm343": { + "displayName": "TM343", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm344": { + "displayName": "TM344", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm345": { + "displayName": "TM345", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm346": { + "displayName": "TM346", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm351": { + "displayName": "TM351", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm352": { + "displayName": "TM352", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm353": { + "displayName": "TM353", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm354": { + "displayName": "TM354", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm355": { + "displayName": "TM355", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm356": { + "displayName": "TM356", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm361": { + "displayName": "TM361", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm362": { + "displayName": "TM362", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm363": { + "displayName": "TM363", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm364": { + "displayName": "TM364", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm365": { + "displayName": "TM365", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm366": { + "displayName": "TM366", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm411": { + "displayName": "TM411", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm412": { + "displayName": "TM412", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm413": { + "displayName": "TM413", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm414": { + "displayName": "TM414", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm415": { + "displayName": "TM415", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm416": { + "displayName": "TM416", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm421": { + "displayName": "TM421", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm422": { + "displayName": "TM422", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm423": { + "displayName": "TM423", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm424": { + "displayName": "TM424", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm425": { + "displayName": "TM425", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm426": { + "displayName": "TM426", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm431": { + "displayName": "TM431", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm432": { + "displayName": "TM432", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm433": { + "displayName": "TM433", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm434": { + "displayName": "TM434", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm435": { + "displayName": "TM435", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm436": { + "displayName": "TM436", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm441": { + "displayName": "TM441", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm442": { + "displayName": "TM442", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm443": { + "displayName": "TM443", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm444": { + "displayName": "TM444", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm445": { + "displayName": "TM445", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm446": { + "displayName": "TM446", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm451": { + "displayName": "TM451", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm452": { + "displayName": "TM452", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm453": { + "displayName": "TM453", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm454": { + "displayName": "TM454", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm455": { + "displayName": "TM455", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm456": { + "displayName": "TM456", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm461": { + "displayName": "TM461", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm462": { + "displayName": "TM462", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm463": { + "displayName": "TM463", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm464": { + "displayName": "TM464", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm465": { + "displayName": "TM465", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm466": { + "displayName": "TM466", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm511": { + "displayName": "TM511", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm512": { + "displayName": "TM512", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm513": { + "displayName": "TM513", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm514": { + "displayName": "TM514", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm515": { + "displayName": "TM515", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm516": { + "displayName": "TM516", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm521": { + "displayName": "TM521", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm522": { + "displayName": "TM522", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm523": { + "displayName": "TM523", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm524": { + "displayName": "TM524", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm525": { + "displayName": "TM525", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm526": { + "displayName": "TM526", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm531": { + "displayName": "TM531", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm532": { + "displayName": "TM532", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm533": { + "displayName": "TM533", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm534": { + "displayName": "TM534", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm535": { + "displayName": "TM535", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm536": { + "displayName": "TM536", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm541": { + "displayName": "TM541", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm542": { + "displayName": "TM542", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm543": { + "displayName": "TM543", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm544": { + "displayName": "TM544", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm545": { + "displayName": "TM545", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm546": { + "displayName": "TM546", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm551": { + "displayName": "TM551", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm552": { + "displayName": "TM552", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm553": { + "displayName": "TM553", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm554": { + "displayName": "TM554", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm555": { + "displayName": "TM555", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm556": { + "displayName": "TM556", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm561": { + "displayName": "TM561", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm562": { + "displayName": "TM562", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm563": { + "displayName": "TM563", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm564": { + "displayName": "TM564", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm565": { + "displayName": "TM565", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm566": { + "displayName": "TM566", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm611": { + "displayName": "TM611", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm612": { + "displayName": "TM612", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm613": { + "displayName": "TM613", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm614": { + "displayName": "TM614", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm615": { + "displayName": "TM615", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm616": { + "displayName": "TM616", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm621": { + "displayName": "TM621", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm622": { + "displayName": "TM622", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm623": { + "displayName": "TM623", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm624": { + "displayName": "TM624", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm625": { + "displayName": "TM625", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm626": { + "displayName": "TM626", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm631": { + "displayName": "TM631", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm632": { + "displayName": "TM632", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm633": { + "displayName": "TM633", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm634": { + "displayName": "TM634", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm635": { + "displayName": "TM635", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm636": { + "displayName": "TM636", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm641": { + "displayName": "TM641", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm642": { + "displayName": "TM642", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm643": { + "displayName": "TM643", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm644": { + "displayName": "TM644", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm645": { + "displayName": "TM645", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm646": { + "displayName": "TM646", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm651": { + "displayName": "TM651", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm652": { + "displayName": "TM652", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm653": { + "displayName": "TM653", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm654": { + "displayName": "TM654", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm655": { + "displayName": "TM655", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm656": { + "displayName": "TM656", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm661": { + "displayName": "TM661", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm662": { + "displayName": "TM662", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm663": { + "displayName": "TM663", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm664": { + "displayName": "TM664", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + }, + "tm665": { + "displayName": "TM665", + "type": "RPNValue", + "defaultValue": 0, + "description": "Defines the second-order terms of the element" + } + }, + "MONITOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the monitor." + } + }, + "MULTIPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "lrad": { + "displayName": "LRAD", + "type": "RPNValue", + "defaultValue": 0, + "description": "A fictitious length, which was originally just used to compute synchrotron radiation effects." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + }, + "knl": { + "displayName": "KNL", + "type": "FloatArray", + "defaultValue": "0", + "description": "The normal multipole coefficients from order zero to the maximum." + }, + "ksl": { + "displayName": "KSL", + "type": "FloatArray", + "defaultValue": "0", + "description": "The skew multipole coefficients from order zero to the maximum." + } + }, + "NLLENS": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "knll": { + "displayName": "KNLL [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The integrated strength of lens." + }, + "cnll": { + "displayName": "CNLL [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The dimensional parameter of lens." + } + }, + "OCTUPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The octupole length." + }, + "k3": { + "displayName": "K3", + "type": "RPNValue", + "defaultValue": 0, + "description": "The normal octupole coefficient." + }, + "k3s": { + "displayName": "K3S", + "type": "RPNValue", + "defaultValue": 0, + "description": "The skew octupole coefficient." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "PLACEHOLDER": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the placeholder." + } + }, + "QUADRUPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The quadrupole length" + }, + "k1": { + "displayName": "K1 [$\\bf m^{-2}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The normal quadrupole coefficient" + }, + "k1s": { + "displayName": "K1S [$\\bf m^{-2}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The skew quadrupole coefficient" + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis" + }, + "thick": { + "displayName": "THICK", + "type": "Boolean", + "defaultValue": "0", + "description": "If this logical flag is set to true the quadrupole is tracked through as a thick-element, instead of being converted into thin-lenses." + } + }, + "RBEND": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the magnet." + }, + "angle": { + "displayName": "ANGLE [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The bend angle." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + }, + "k1": { + "displayName": "K1 [$\\bf m^{-2}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The quadrupole coefficient." + }, + "k2": { + "displayName": "K2 [$\\bf m^{-3}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The sextupole coefficient." + }, + "e1": { + "displayName": "E1 [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle for the entrance pole face." + }, + "e2": { + "displayName": "E2 [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle for the exit pole face." + }, + "fint": { + "displayName": "FINT", + "type": "RPNValue", + "defaultValue": 0, + "description": "The fringe field integral at the entrance and exit of the bend." + }, + "fintx": { + "displayName": "FINTX", + "type": "RPNValue", + "defaultValue": -1, + "description": "If defined and positive, the fringe field integral at the exit of the element, overriding FINT for the exit." + }, + "hgap": { + "displayName": "HGAP [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The half gap of the magnet." + }, + "h1": { + "displayName": "H1 [$\\bf m^{-1}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The curvature of the entrance pole face." + }, + "h2": { + "displayName": "H2 [$\\bf m^{-1}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The curvature of the exit pole face." + }, + "add_angle": { + "displayName": "ADD_ANGLE", + "type": "FloatArray", + "defaultValue": "0 0 0 0 0", + "description": "An array of (maximum 5) bending angles for multiple passes." + }, + "thick": { + "displayName": "THICK", + "type": "Boolean", + "defaultValue": "0", + "description": "If this logical flag is set to true the bending magnet will be tracked through as a thick-element, instead of being converted into thin-lenses." + } + }, + "RCOLLIMATOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The collimator length" + }, + "xsize": { + "displayName": "XSIZE", + "type": "RPNValue", + "defaultValue": 0, + "description": "*OBSOLETE* The horizontal half-aperture." + }, + "ysize": { + "displayName": "YSIZE", + "type": "RPNValue", + "defaultValue": 0, + "description": "*OBSOLETE* The horizontal half-aperture." + } + }, + "RFCAVITY": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the cavity" + }, + "volt": { + "displayName": "VOLT [MV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The peak RF voltage" + }, + "lag": { + "displayName": "LAG [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The initial phase lag." + }, + "freq": { + "displayName": "FREQ [MHz]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The frequency." + }, + "harmon": { + "displayName": "HARMON", + "type": "Integer", + "defaultValue": 0, + "description": "The harmonic number." + } + }, + "RFMULTIPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "volt": { + "displayName": "VOLT [MV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The peak RF voltage." + }, + "lag": { + "displayName": "LAG [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The phase lag." + }, + "harmon": { + "displayName": "HARMON", + "type": "Integer", + "defaultValue": 0, + "description": "The harmonic number." + }, + "freq": { + "displayName": "FREQ [MHz]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The frequency." + }, + "lrad": { + "displayName": "LRAD", + "type": "RPNValue", + "defaultValue": 0, + "description": "A fictitious length, which was originally just used to compute synchrotron radiation effects." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + }, + "knll": { + "displayName": "KNLL [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The integrated strength of lens." + }, + "ksl": { + "displayName": "KSL", + "type": "FloatArray", + "defaultValue": "0", + "description": "The skew rfmultipole coefficients from order zero to the maximum." + }, + "pnl": { + "displayName": "PNL", + "type": "FloatArray", + "defaultValue": "0", + "description": "The phase for each normal rfmultipole coefficients from order zero to the maximum." + }, + "psl": { + "displayName": "PSL", + "type": "FloatArray", + "defaultValue": "0", + "description": "The phase for each skew rfmultipole coefficients from order zero to the maximum." + } + }, + "SBEND": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the magnet." + }, + "angle": { + "displayName": "ANGLE [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The bend angle." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + }, + "k1": { + "displayName": "K1 [$\\bf m^{-2}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The quadrupole coefficient." + }, + "k2": { + "displayName": "K2 [$\\bf m^{-3}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The sextupole coefficient." + }, + "e1": { + "displayName": "E1 [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle for the entrance pole face." + }, + "e2": { + "displayName": "E2 [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle for the exit pole face." + }, + "fint": { + "displayName": "FINT", + "type": "RPNValue", + "defaultValue": 0, + "description": "The fringe field integral at the entrance and exit of the bend." + }, + "fintx": { + "displayName": "FINTX", + "type": "RPNValue", + "defaultValue": -1, + "description": "If defined and positive, the fringe field integral at the exit of the element, overriding FINT for the exit." + }, + "hgap": { + "displayName": "HGAP [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The half gap of the magnet." + }, + "h1": { + "displayName": "H1 [$\\bf m^{-1}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The curvature of the entrance pole face." + }, + "h2": { + "displayName": "H2 [$\\bf m^{-1}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The curvature of the exit pole face." + }, + "thick": { + "displayName": "THICK", + "type": "Boolean", + "defaultValue": "0", + "description": "If this logical flag is set to true the bending magnet will be tracked through as a thick-element, instead of being converted into thin-lenses." + } + }, + "SEXTUPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The sextupole length, " + }, + "k2": { + "displayName": "K2 [$\\bf m^{-3}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The sextupole coefficient." + }, + "k2s": { + "displayName": "K2S [$\\bf m^{-3}$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The skew sextupole coefficient." + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "SOLENOID": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the solenoid." + }, + "ks": { + "displayName": "KS [rad/m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The solenoid strength." + }, + "ksi": { + "displayName": "KSI [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The solenoid integrated strength." + } + }, + "SROTATION": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "angle": { + "displayName": "ANGLE [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle psi." + } + }, + "TRANSLATION": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "dx": { + "displayName": "DX", + "type": "RPNValue", + "defaultValue": 0, + "description": "Translate position of x." + }, + "dy": { + "displayName": "DY", + "type": "RPNValue", + "defaultValue": 0, + "description": "Translate position of y." + }, + "ds": { + "displayName": "DS", + "type": "RPNValue", + "defaultValue": 0, + "description": "Introduce virtual drift." + } + }, + "TWCAVITY": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the cavity" + }, + "volt": { + "displayName": "VOLT [MV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The peak RF voltage" + }, + "lag": { + "displayName": "LAG [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The initial phase lag." + }, + "freq": { + "displayName": "FREQ [MHz]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The frequency." + }, + "psi": { + "displayName": "PSI", + "type": "RPNValue", + "defaultValue": 0 + }, + "delta_lag": { + "displayName": "DELTA_LAG", + "type": "RPNValue", + "defaultValue": 0 + } + }, + "VACDIPOLE": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the device." + }, + "volt": { + "displayName": "VOLT [MV]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The amplitude of the kick." + }, + "lag": { + "displayName": "LAG [2$\\pi$]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The initial phase lag." + }, + "freq": { + "displayName": "FREQ [MHz]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The frequency." + }, + "ramp1": { + "displayName": "RAMP1", + "type": "Integer", + "defaultValue": 0, + "description": "Starting turn of amplitude ramp-up." + }, + "ramp2": { + "displayName": "RAMP2", + "type": "Integer", + "defaultValue": 0, + "description": "Last turn of amplitude ramp-up." + }, + "ramp3": { + "displayName": "RAMP3", + "type": "Integer", + "defaultValue": 0, + "description": "Starting turn of amplitude ramp-down." + }, + "ramp4": { + "displayName": "RAMP4", + "type": "Integer", + "defaultValue": 0, + "description": "Last turn of amplitude ramp-down." + } + }, + "VKICKER": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the closed orbit corrector." + }, + "kick": { + "displayName": "KICK", + "type": "RPNValue", + "defaultValue": 0, + "description": "The momentum change $\\delta PY$" + }, + "tilt": { + "displayName": "TILT [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The roll angle about the longitudinal axis." + } + }, + "VMONITOR": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "l": { + "displayName": "L [m]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The length of the monitor." + } + }, + "XROTATION": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "angle": { + "displayName": "ANGLE [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle." + } + }, + "YROTATION": { + "name": { + "displayName": "Name", + "type": "ValidatedString" + }, + "apertype": { + "displayName": "APERTYPE", + "type": "ApertureType", + "defaultValue": "circle" + }, + "aperture": { + "displayName": "APERTURE", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_offset": { + "displayName": "APER_OFFSET", + "type": "FloatArray", + "defaultValue": "0" + }, + "aper_tol": { + "displayName": "APER_TOL", + "type": "FloatArray", + "defaultValue": "0 0 0" + }, + "angle": { + "displayName": "ANGLE [rad]", + "type": "RPNValue", + "defaultValue": 0, + "description": "The rotation angle." + } + } + }, + "type": { + "ApertureType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "circle", + "Circle" + ], + [ + "rectangle", + "Rectangle" + ], + [ + "ellipse", + "Ellipse" + ], + [ + "rectcircle", + "Rectangle/Circle Superposition" + ], + [ + "rectellipse", + "Rectangle/Ellipse Superposition" + ], + [ + "racetrack", + "Racetrack" + ], + [ + "octagon", + "Octagon" + ] + ] + } + }, + "BeambeamBbshape": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Gaussian" + ], + [ + "2", + "Trapezoidal" + ], + [ + "3", + "Hollow Parabolic" + ] + ] + } + }, + "BeambeamBbdir": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "-1", + "Beams move in opposite direction" + ], + [ + "0", + "Opposite beam does not move" + ], + [ + "1", + "Beams move in same direction" + ] + ] + } + }, + "BeamDefinition": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "energy", + "From Energy" + ], + [ + "pc", + "From PC" + ], + [ + "gamma", + "From Gamma" + ], + [ + "beta", + "From Beta" + ], + [ + "brho", + "From BRHO" + ] + ] + } + }, + "CommandMakethinStyle": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "teapot", + "Teapot" + ], + [ + "simple", + "Simple" + ], + [ + "collim", + "Collim" + ], + [ + "hybrid", + "Hybrid" + ] + ] + } + }, + "CommandTemplate": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "matching", + "Beamline Matching" + ], + [ + "particle", + "Particle Tracking" + ], + [ + "none", + "No Template" + ] + ] + } + }, + "CommandVarySlope": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Increase" + ], + [ + "-1", + "Decrease" + ], + [ + "-none-", + "None" + ] + ] + } + }, + "ParticleType": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "positron", + "Positron" + ], + [ + "electron", + "Electron" + ], + [ + "proton", + "Proton" + ], + [ + "antiproton", + "Anti-proton" + ], + [ + "posmuon", + "Positive Muon" + ], + [ + "negmuon", + "Negative Muon" + ], + [ + "ion", + "Ion" + ], + [ + "other", + "Other" + ] + ] + } + }, + "PhaseSpaceCoordinate": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "x", + "x" + ], + [ + "px", + "Px" + ], + [ + "y", + "y" + ], + [ + "py", + "Py" + ], + [ + "t", + "t" + ], + [ + "pt", + "Pt" + ] + ] + } + }, + "Icase": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "4", + "4" + ], + [ + "5", + "5" + ], + [ + "6", + "6" + ] + ] + } + }, + "SpaceCoordinate": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "x", + "x" + ], + [ + "y", + "y" + ], + [ + "z", + "z" + ] + ] + } + }, + "OptionalBoolean": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "", + "NOT SELECTED" + ], + [ + "1", + "Yes" + ], + [ + "0", + "No" + ] + ] + } + }, + "PtccreatelayoutModel": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "1", + "Drift-Kick-Drift" + ], + [ + "2", + "Matrix-Kick-Matrix" + ], + [ + "3", + "Delta-Matrix-Kick-Matrix" + ] + ] + } + }, + "TwissParameter": { + "base": "Enum", + "config": { + "allowedValues": [ + [ + "alfx", + "alfx" + ], + [ + "alfy", + "alfy" + ], + [ + "betx", + "betx" + ], + [ + "bety", + "bety" + ], + [ + "dpx", + "dpx" + ], + [ + "dpy", + "dpy" + ], + [ + "dx", + "dx" + ], + [ + "dy", + "dy" + ], + [ + "mux", + "mux" + ], + [ + "muy", + "muy" + ], + [ + "s", + "s" + ], + [ + "None", + "None" + ] + ] + } + } + }, + "view": [ + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "beamline.name" + ] + } + } + ], + "title": "Beamline" + }, + "_NAME": "beamline" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "beamlineReport.notes" + ] + } + } + ], + "title": "Lattice" + }, + "_NAME": "beamlineReport" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Main", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.particle", + "command_beam.mass", + "command_beam.charge", + "bunch.beamDefinition", + "command_beam.energy", + "command_beam.pc", + "command_beam.gamma", + "command_beam.beta", + "command_beam.brho" + ] + } + } + ] + }, + { + "name": "Distribution", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bunch.matchTwissParameters", + "simulation.visualizationBeamlineId" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "EX [m]", + "description": "The horizontal emittance.", + "fields": [ + "command_beam.ex", + "command_beam.ey" + ] + }, + { + "label": "Horizontal Beta [m]", + "fields": [ + "bunch.betx", + "bunch.bety" + ] + }, + { + "label": "Horizontal Alpha", + "fields": [ + "bunch.alfx", + "bunch.alfy" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.et", + "command_beam.sigt", + "command_beam.sige" + ] + } + } + ] + }, + { + "name": "Position", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Centroid [m]", + "fields": [ + "bunch.x", + "bunch.y" + ] + }, + { + "label": "Horizontal Canonical Momentum of $p_x$", + "fields": [ + "bunch.px", + "bunch.py" + ] + } + ] + } + } + ] + }, + { + "name": "Particle Count", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bunch.numberOfParticles", + "bunch.randomSeed" + ] + } + } + ] + } + ] + } + } + ], + "advanced": [], + "title": "Bunch" + }, + "_NAME": "bunch" + }, + { + "layout": "panel", + "config": { + "basic": [], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport.x", + "bunchReport.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport.histogramBins", + "bunchReport.colorMap", + "bunchReport.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Value to Plot", + "fields": [ + "elementAnimation.x", + "elementAnimation.y1" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.framesPerSecond", + "elementAnimation.histogramBins", + "elementAnimation.aspectRatio", + "elementAnimation.colorMap", + "elementAnimation.notes" + ] + } + } + ], + "title": "Output Report" + }, + "_NAME": "heatmapFrameAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.framesPerSecond", + "elementAnimation.includeLattice", + "elementAnimation.notes" + ] + } + } + ], + "title": "Output Report" + }, + "_NAME": "plotFrameAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "Match Summary" + }, + "_NAME": "matchSummaryAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.particle", + "command_beam.mass", + "command_beam.charge", + "command_beam.energy", + "command_beam.pc", + "command_beam.gamma", + "command_beam.beta", + "command_beam.brho", + "command_beam.ex", + "command_beam.exn", + "command_beam.ey", + "command_beam.eyn", + "command_beam.et", + "command_beam.sequence", + "command_beam.sigt", + "command_beam.sige", + "command_beam.kbunch", + "command_beam.npart", + "command_beam.bcurrent", + "command_beam.bunched", + "command_beam.radiate", + "command_beam.bv" + ] + } + } + ], + "title": "beam" + }, + "_NAME": "command_beam" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beta0.betx", + "command_beta0.alfx", + "command_beta0.bety", + "command_beta0.mux", + "command_beta0.alfy", + "command_beta0.muy", + "command_beta0.x", + "command_beta0.px", + "command_beta0.y", + "command_beta0.py", + "command_beta0.t", + "command_beta0.pt", + "command_beta0.dx", + "command_beta0.dpx", + "command_beta0.dy", + "command_beta0.dpy", + "command_beta0.wx", + "command_beta0.phix", + "command_beta0.dmux", + "command_beta0.wy", + "command_beta0.phiy", + "command_beta0.dmuy", + "command_beta0.ddx", + "command_beta0.ddpx", + "command_beta0.ddy", + "command_beta0.ddpy", + "command_beta0.r11", + "command_beta0.r12", + "command_beta0.r21", + "command_beta0.r22", + "command_beta0.energy" + ] + } + } + ], + "title": "beta0" + }, + "_NAME": "command_beta0" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_constraint.sequence", + "command_constraint.range", + "command_constraint.alfx", + "command_constraint.alfy", + "command_constraint.betx", + "command_constraint.bety", + "command_constraint.dpx", + "command_constraint.dpy", + "command_constraint.dx", + "command_constraint.dy", + "command_constraint.mux", + "command_constraint.muy", + "command_constraint.px", + "command_constraint.py", + "command_constraint.x", + "command_constraint.y" + ] + } + } + ], + "title": "constraint" + }, + "_NAME": "command_constraint" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ealign.dx", + "command_ealign.dy", + "command_ealign.ds", + "command_ealign.dphi", + "command_ealign.dtheta", + "command_ealign.dpsi", + "command_ealign.mrex", + "command_ealign.mrey", + "command_ealign.mscalx", + "command_ealign.mscaly", + "command_ealign.arex", + "command_ealign.arey" + ] + } + } + ], + "title": "ealign" + }, + "_NAME": "command_ealign" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_emit.deltap", + "command_emit.tol" + ] + } + } + ], + "title": "emit" + }, + "_NAME": "command_emit" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "endmatch" + }, + "_NAME": "command_endmatch" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_global.sequence", + "command_global.q1", + "command_global.q2", + "command_global.dq1", + "command_global.dq2" + ] + } + } + ], + "title": "global" + }, + "_NAME": "command_global" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_jacobian.calls", + "command_jacobian.tolerance", + "command_jacobian.repeat", + "command_jacobian.strategy", + "command_jacobian.cool", + "command_jacobian.balance", + "command_jacobian.random" + ] + } + } + ], + "title": "jacobian" + }, + "_NAME": "command_jacobian" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_lmdif.calls", + "command_lmdif.tolerance" + ] + } + } + ], + "title": "lmdif" + }, + "_NAME": "command_lmdif" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_makethin.sequence", + "command_makethin.style", + "command_makethin.makedipedge" + ] + } + } + ], + "title": "makethin" + }, + "_NAME": "command_makethin" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_match.sequence", + "command_match.alfx", + "command_match.alfy", + "command_match.betx", + "command_match.bety", + "command_match.deltap", + "command_match.dpx", + "command_match.dpy", + "command_match.dx", + "command_match.dy", + "command_match.mux", + "command_match.muy", + "command_match.px", + "command_match.py", + "command_match.x", + "command_match.y" + ] + } + } + ], + "title": "match" + }, + "_NAME": "command_match" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_migrad.calls", + "command_migrad.tolerance", + "command_migrad.strategy" + ] + } + } + ], + "title": "migrad" + }, + "_NAME": "command_migrad" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_option.bborbit", + "command_option.debug", + "command_option.echo", + "command_option.echomacro", + "command_option.info", + "command_option.no_fatal_stop", + "command_option.rbarc", + "command_option.reset", + "command_option.sympl", + "command_option.tell", + "command_option.thin_foc", + "command_option.threader", + "command_option.trace", + "command_option.twiss_print", + "command_option.verbose", + "command_option.verify", + "command_option.warn" + ] + } + } + ], + "title": "option" + }, + "_NAME": "command_option" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_create_layout.time", + "command_ptc_create_layout.model", + "command_ptc_create_layout.method", + "command_ptc_create_layout.nst", + "command_ptc_create_layout.exact", + "command_ptc_create_layout.offset_deltap", + "command_ptc_create_layout.errors_out", + "command_ptc_create_layout.magnet_name", + "command_ptc_create_layout.resplit", + "command_ptc_create_layout.thin", + "command_ptc_create_layout.xbend", + "command_ptc_create_layout.even" + ] + } + } + ], + "title": "ptc_create_layout" + }, + "_NAME": "command_ptc_create_layout" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_create_universe.sector_nmul_max", + "command_ptc_create_universe.sector_nmul", + "command_ptc_create_universe.ntpsa", + "command_ptc_create_universe.symprint" + ] + } + } + ], + "title": "ptc_create_universe" + }, + "_NAME": "command_ptc_create_universe" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "ptc_create_end" + }, + "_NAME": "command_ptc_end" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_normal.closed_orbit", + "command_ptc_normal.deltap", + "command_ptc_normal.icase", + "command_ptc_normal.map_table", + "command_ptc_normal.no", + "command_ptc_normal.normal" + ] + } + } + ], + "title": "ptc_normal" + }, + "_NAME": "command_ptc_normal" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_observe.place" + ] + } + } + ], + "title": "ptc_observe" + }, + "_NAME": "command_ptc_observe" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_select.table", + "command_ptc_select.column", + "command_ptc_select.polynomial", + "command_ptc_select.monomial", + "command_ptc_select.parametric", + "command_ptc_select.quantity" + ] + } + } + ], + "title": "ptc_select" + }, + "_NAME": "command_ptc_select" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_setswitch.debuglevel", + "command_ptc_setswitch.exact_mis", + "command_ptc_setswitch.totalpath", + "command_ptc_setswitch.radiation", + "command_ptc_setswitch.envelope", + "command_ptc_setswitch.stochastic", + "command_ptc_setswitch.modulation", + "command_ptc_setswitch.fringe" + ] + } + } + ], + "title": "ptc_setswitch" + }, + "_NAME": "command_ptc_setswitch" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_start.x", + "command_ptc_start.px", + "command_ptc_start.y", + "command_ptc_start.py", + "command_ptc_start.t", + "command_ptc_start.pt", + "command_ptc_start.fx", + "command_ptc_start.phix", + "command_ptc_start.fy", + "command_ptc_start.phiy", + "command_ptc_start.ft", + "command_ptc_start.phit" + ] + } + } + ], + "title": "ptc_start" + }, + "_NAME": "command_ptc_start" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_track.deltap", + "command_ptc_track.icase", + "command_ptc_track.closed_orbit", + "command_ptc_track.element_by_element", + "command_ptc_track.turns", + "command_ptc_track.maxaper", + "command_ptc_track.norm_no", + "command_ptc_track.file", + "command_ptc_track.norm_out", + "command_ptc_track.ffile", + "command_ptc_track.radiation", + "command_ptc_track.radiation_model1", + "command_ptc_track.radiation_energy_loss", + "command_ptc_track.radiation_quad", + "command_ptc_track.beam_envelope", + "command_ptc_track.space_charge" + ] + } + } + ], + "title": "ptc_track" + }, + "_NAME": "command_ptc_track" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "ptc_track_end" + }, + "_NAME": "command_ptc_track_end" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_trackline.turns", + "command_ptc_trackline.file", + "command_ptc_trackline.everystep", + "command_ptc_trackline.gcs" + ] + } + } + ], + "title": "ptc_trackline" + }, + "_NAME": "command_ptc_trackline" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_twiss.icase", + "command_ptc_twiss.deltap", + "command_ptc_twiss.closed_orbit", + "command_ptc_twiss.deltap_dependency", + "command_ptc_twiss.slice_magnets", + "command_ptc_twiss.range", + "command_ptc_twiss.file", + "command_ptc_twiss.initial_matrix_manual", + "command_ptc_twiss.initial_map_manual", + "command_ptc_twiss.beta0", + "command_ptc_twiss.ignore_map_orbit", + "command_ptc_twiss.ring_parameters", + "command_ptc_twiss.normal", + "command_ptc_twiss.trackrdts", + "command_ptc_twiss.betx", + "command_ptc_twiss.alfx", + "command_ptc_twiss.mux", + "command_ptc_twiss.bety", + "command_ptc_twiss.alfy", + "command_ptc_twiss.muy", + "command_ptc_twiss.betz", + "command_ptc_twiss.alfz", + "command_ptc_twiss.dx", + "command_ptc_twiss.dpx", + "command_ptc_twiss.dy", + "command_ptc_twiss.dpy", + "command_ptc_twiss.x", + "command_ptc_twiss.px", + "command_ptc_twiss.y", + "command_ptc_twiss.py", + "command_ptc_twiss.t", + "command_ptc_twiss.pt", + "command_ptc_twiss.re11", + "command_ptc_twiss.re12", + "command_ptc_twiss.re13", + "command_ptc_twiss.re14", + "command_ptc_twiss.re15", + "command_ptc_twiss.re16", + "command_ptc_twiss.re21", + "command_ptc_twiss.re22", + "command_ptc_twiss.re23", + "command_ptc_twiss.re24", + "command_ptc_twiss.re25", + "command_ptc_twiss.re26", + "command_ptc_twiss.re31", + "command_ptc_twiss.re32", + "command_ptc_twiss.re33", + "command_ptc_twiss.re34", + "command_ptc_twiss.re35", + "command_ptc_twiss.re36", + "command_ptc_twiss.re41", + "command_ptc_twiss.re42", + "command_ptc_twiss.re43", + "command_ptc_twiss.re44", + "command_ptc_twiss.re45", + "command_ptc_twiss.re46", + "command_ptc_twiss.re51", + "command_ptc_twiss.re52", + "command_ptc_twiss.re53", + "command_ptc_twiss.re54", + "command_ptc_twiss.re55", + "command_ptc_twiss.re56", + "command_ptc_twiss.re61", + "command_ptc_twiss.re62", + "command_ptc_twiss.re63", + "command_ptc_twiss.re64", + "command_ptc_twiss.re65", + "command_ptc_twiss.re66" + ] + } + } + ], + "title": "ptc_twiss" + }, + "_NAME": "command_ptc_twiss" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_resbeam.sequence" + ] + } + } + ], + "title": "resbeam" + }, + "_NAME": "command_resbeam" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_savebeta.label", + "command_savebeta.place", + "command_savebeta.sequence" + ] + } + } + ], + "title": "savebeta" + }, + "_NAME": "command_savebeta" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_select.class", + "command_select.clear", + "command_select.column", + "command_select.flag", + "command_select.full", + "command_select.pattern", + "command_select.range", + "command_select.sequence", + "command_select.slice", + "command_select.thick" + ] + } + } + ], + "title": "select" + }, + "_NAME": "command_select" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_set.format", + "command_set.sequence" + ] + } + } + ], + "title": "set" + }, + "_NAME": "command_set" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_show.command" + ] + } + } + ], + "title": "show" + }, + "_NAME": "command_show" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_sodd.detune", + "command_sodd.distort1", + "command_sodd.distort2", + "command_sodd.multipole_order_range", + "command_sodd.noprint ", + "command_sodd.nosixtrack", + "command_sodd.print_all", + "command_sodd.print_at_end", + "command_sodd.start_stop" + ] + } + } + ], + "title": "sodd" + }, + "_NAME": "command_sodd" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_touschek.tolerance", + "command_touschek.file" + ] + } + } + ], + "title": "touschek" + }, + "_NAME": "command_touschek" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_twiss.line", + "command_twiss.range", + "command_twiss.deltap", + "command_twiss.chrom", + "command_twiss.centre", + "command_twiss.tolerance", + "command_twiss.file", + "command_twiss.rmatrix", + "command_twiss.sectormap", + "command_twiss.sectortable", + "command_twiss.sectorfile", + "command_twiss.sectorpure", + "command_twiss.keeporbit", + "command_twiss.useorbit", + "command_twiss.ripken", + "command_twiss.betx", + "command_twiss.alfx", + "command_twiss.mux", + "command_twiss.dx", + "command_twiss.dpx", + "command_twiss.bety", + "command_twiss.muy", + "command_twiss.alfy", + "command_twiss.dy", + "command_twiss.dpy", + "command_twiss.x", + "command_twiss.px", + "command_twiss.y", + "command_twiss.py", + "command_twiss.t", + "command_twiss.pt", + "command_twiss.wx", + "command_twiss.phix", + "command_twiss.dmux", + "command_twiss.ddx", + "command_twiss.ddpx", + "command_twiss.wy", + "command_twiss.phiy", + "command_twiss.dmuy", + "command_twiss.ddy", + "command_twiss.ddpy", + "command_twiss.r11", + "command_twiss.r12", + "command_twiss.r21", + "command_twiss.r22" + ] + } + } + ], + "title": "twiss" + }, + "_NAME": "command_twiss" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_use.sequence", + "command_use.period" + ] + } + } + ], + "title": "use" + }, + "_NAME": "command_use" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_vary.name", + "command_vary.step", + "command_vary.lower", + "command_vary.upper", + "command_vary.slope", + "command_vary.opt" + ] + } + } + ], + "title": "vary" + }, + "_NAME": "command_vary" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.visualizationBeamlineId", + "bunch.numberOfParticles", + "simulation.computeTwissFromParticles" + ] + } + } + ], + "advanced": [], + "title": "Simulation Settings" + }, + "_NAME": "simulationSettings" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "Simulation Status" + }, + "_NAME": "simulationStatus" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "twissEllipseReport.dim" + ] + } + } + ], + "title": "Twiss Ellipse" + }, + "_NAME": "twissEllipseReport" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.y1", + "twissFromParticlesAnimation.y2", + "twissFromParticlesAnimation.y3" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.includeLattice", + "twissFromParticlesAnimation.notes" + ] + } + } + ], + "title": "Twiss From Particles" + }, + "_NAME": "twissFromParticlesAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.includeLattice" + ] + } + } + ], + "title": "Twiss Parameters" + }, + "_NAME": "twissAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "twissReport.y1", + "twissReport.y2", + "twissReport.y3", + "twissReport.includeLattice" + ] + } + } + ], + "title": "Twiss Parameters" + }, + "_NAME": "twissReport" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "BEAMBEAM.name", + "BEAMBEAM.sigx", + "BEAMBEAM.sigy", + "BEAMBEAM.xma", + "BEAMBEAM.yma", + "BEAMBEAM.charge", + "BEAMBEAM.bbshape", + "BEAMBEAM.width", + "BEAMBEAM.bbdir", + "BEAMBEAM.apertype", + "BEAMBEAM.aperture", + "BEAMBEAM.aper_offset", + "BEAMBEAM.aper_tol" + ] + } + } + ], + "title": "BEAMBEAM" + }, + "_NAME": "BEAMBEAM" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CHANGEREF.name", + "CHANGEREF.patch_ang", + "CHANGEREF.patch_trans", + "CHANGEREF.apertype", + "CHANGEREF.aperture", + "CHANGEREF.aper_offset", + "CHANGEREF.aper_tol" + ] + } + } + ], + "title": "CHANGEREF" + }, + "_NAME": "CHANGEREF" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "COLLIMATOR.name", + "COLLIMATOR.l", + "COLLIMATOR.apertype", + "COLLIMATOR.aperture", + "COLLIMATOR.aper_offset", + "COLLIMATOR.aper_tol" + ] + } + } + ], + "title": "COLLIMATOR" + }, + "_NAME": "COLLIMATOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CRABCAVITY.name", + "CRABCAVITY.l", + "CRABCAVITY.volt", + "CRABCAVITY.lag", + "CRABCAVITY.freq", + "CRABCAVITY.rv1", + "CRABCAVITY.rv2", + "CRABCAVITY.rv3", + "CRABCAVITY.rv4", + "CRABCAVITY.rph1", + "CRABCAVITY.rph2", + "CRABCAVITY.lagf", + "CRABCAVITY.apertype", + "CRABCAVITY.aperture", + "CRABCAVITY.aper_offset", + "CRABCAVITY.aper_tol" + ] + } + } + ], + "title": "CRABCAVITY" + }, + "_NAME": "CRABCAVITY" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DIPEDGE.name", + "DIPEDGE.h", + "DIPEDGE.e1", + "DIPEDGE.fint", + "DIPEDGE.hgap", + "DIPEDGE.tilt", + "DIPEDGE.apertype", + "DIPEDGE.aperture", + "DIPEDGE.aper_offset", + "DIPEDGE.aper_tol" + ] + } + } + ], + "title": "DIPEDGE" + }, + "_NAME": "DIPEDGE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DRIFT.name", + "DRIFT.l" + ] + } + } + ], + "title": "DRIFT" + }, + "_NAME": "DRIFT" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "ECOLLIMATOR.name", + "ECOLLIMATOR.l", + "ECOLLIMATOR.xsize", + "ECOLLIMATOR.ysize", + "ECOLLIMATOR.apertype", + "ECOLLIMATOR.aperture", + "ECOLLIMATOR.aper_offset", + "ECOLLIMATOR.aper_tol" + ] + } + } + ], + "title": "ECOLLIMATOR" + }, + "_NAME": "ECOLLIMATOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HACDIPOLE.name", + "HACDIPOLE.l", + "HACDIPOLE.volt", + "HACDIPOLE.freq", + "HACDIPOLE.lag", + "HACDIPOLE.ramp1", + "HACDIPOLE.ramp2", + "HACDIPOLE.ramp3", + "HACDIPOLE.ramp4", + "HACDIPOLE.apertype", + "HACDIPOLE.aperture", + "HACDIPOLE.aper_offset", + "HACDIPOLE.aper_tol" + ] + } + } + ], + "title": "HACDIPOLE" + }, + "_NAME": "HACDIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HKICKER.name", + "HKICKER.l", + "HKICKER.kick", + "HKICKER.tilt", + "HKICKER.apertype", + "HKICKER.aperture", + "HKICKER.aper_offset", + "HKICKER.aper_tol" + ] + } + } + ], + "title": "HKICKER" + }, + "_NAME": "HKICKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HMONITOR.name", + "HMONITOR.l", + "HMONITOR.apertype", + "HMONITOR.aperture", + "HMONITOR.aper_offset", + "HMONITOR.aper_tol" + ] + } + } + ], + "title": "HMONITOR" + }, + "_NAME": "HMONITOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "INSTRUMENT.name", + "INSTRUMENT.l", + "INSTRUMENT.apertype", + "INSTRUMENT.aperture", + "INSTRUMENT.aper_offset", + "INSTRUMENT.aper_tol" + ] + } + } + ], + "title": "INSTRUMENT" + }, + "_NAME": "INSTRUMENT" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "KICKER.name", + "KICKER.l", + "KICKER.hkick", + "KICKER.vkick", + "KICKER.tilt", + "KICKER.apertype", + "KICKER.aperture", + "KICKER.aper_offset", + "KICKER.aper_tol" + ] + } + } + ], + "title": "KICKER" + }, + "_NAME": "KICKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MARKER.name", + "MARKER.apertype", + "MARKER.aperture", + "MARKER.aper_offset", + "MARKER.aper_tol" + ] + } + } + ], + "title": "MARKER" + }, + "_NAME": "MARKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MATRIX.name", + "MATRIX.l", + "MATRIX.kick1", + "MATRIX.kick6", + "MATRIX.rm11", + "MATRIX.rm66", + "MATRIX.tm111", + "MATRIX.tm666", + "MATRIX.kick2", + "MATRIX.kick3", + "MATRIX.kick4", + "MATRIX.kick5", + "MATRIX.rm12", + "MATRIX.rm13", + "MATRIX.rm14", + "MATRIX.rm15", + "MATRIX.rm16", + "MATRIX.rm21", + "MATRIX.rm22", + "MATRIX.rm23", + "MATRIX.rm24", + "MATRIX.rm25", + "MATRIX.rm26", + "MATRIX.rm31", + "MATRIX.rm32", + "MATRIX.rm33", + "MATRIX.rm34", + "MATRIX.rm35", + "MATRIX.rm36", + "MATRIX.rm41", + "MATRIX.rm42", + "MATRIX.rm43", + "MATRIX.rm44", + "MATRIX.rm45", + "MATRIX.rm46", + "MATRIX.rm51", + "MATRIX.rm52", + "MATRIX.rm53", + "MATRIX.rm54", + "MATRIX.rm55", + "MATRIX.rm56", + "MATRIX.rm61", + "MATRIX.rm62", + "MATRIX.rm63", + "MATRIX.rm64", + "MATRIX.rm65", + "MATRIX.tm112", + "MATRIX.tm113", + "MATRIX.tm114", + "MATRIX.tm115", + "MATRIX.tm116", + "MATRIX.tm121", + "MATRIX.tm122", + "MATRIX.tm123", + "MATRIX.tm124", + "MATRIX.tm125", + "MATRIX.tm126", + "MATRIX.tm131", + "MATRIX.tm132", + "MATRIX.tm133", + "MATRIX.tm134", + "MATRIX.tm135", + "MATRIX.tm136", + "MATRIX.tm141", + "MATRIX.tm142", + "MATRIX.tm143", + "MATRIX.tm144", + "MATRIX.tm145", + "MATRIX.tm146", + "MATRIX.tm151", + "MATRIX.tm152", + "MATRIX.tm153", + "MATRIX.tm154", + "MATRIX.tm155", + "MATRIX.tm156", + "MATRIX.tm161", + "MATRIX.tm162", + "MATRIX.tm163", + "MATRIX.tm164", + "MATRIX.tm165", + "MATRIX.tm166", + "MATRIX.tm211", + "MATRIX.tm212", + "MATRIX.tm213", + "MATRIX.tm214", + "MATRIX.tm215", + "MATRIX.tm216", + "MATRIX.tm221", + "MATRIX.tm222", + "MATRIX.tm223", + "MATRIX.tm224", + "MATRIX.tm225", + "MATRIX.tm226", + "MATRIX.tm231", + "MATRIX.tm232", + "MATRIX.tm233", + "MATRIX.tm234", + "MATRIX.tm235", + "MATRIX.tm236", + "MATRIX.tm241", + "MATRIX.tm242", + "MATRIX.tm243", + "MATRIX.tm244", + "MATRIX.tm245", + "MATRIX.tm246", + "MATRIX.tm251", + "MATRIX.tm252", + "MATRIX.tm253", + "MATRIX.tm254", + "MATRIX.tm255", + "MATRIX.tm256", + "MATRIX.tm261", + "MATRIX.tm262", + "MATRIX.tm263", + "MATRIX.tm264", + "MATRIX.tm265", + "MATRIX.tm266", + "MATRIX.tm311", + "MATRIX.tm312", + "MATRIX.tm313", + "MATRIX.tm314", + "MATRIX.tm315", + "MATRIX.tm316", + "MATRIX.tm321", + "MATRIX.tm322", + "MATRIX.tm323", + "MATRIX.tm324", + "MATRIX.tm325", + "MATRIX.tm326", + "MATRIX.tm331", + "MATRIX.tm332", + "MATRIX.tm333", + "MATRIX.tm334", + "MATRIX.tm335", + "MATRIX.tm336", + "MATRIX.tm341", + "MATRIX.tm342", + "MATRIX.tm343", + "MATRIX.tm344", + "MATRIX.tm345", + "MATRIX.tm346", + "MATRIX.tm351", + "MATRIX.tm352", + "MATRIX.tm353", + "MATRIX.tm354", + "MATRIX.tm355", + "MATRIX.tm356", + "MATRIX.tm361", + "MATRIX.tm362", + "MATRIX.tm363", + "MATRIX.tm364", + "MATRIX.tm365", + "MATRIX.tm366", + "MATRIX.tm411", + "MATRIX.tm412", + "MATRIX.tm413", + "MATRIX.tm414", + "MATRIX.tm415", + "MATRIX.tm416", + "MATRIX.tm421", + "MATRIX.tm422", + "MATRIX.tm423", + "MATRIX.tm424", + "MATRIX.tm425", + "MATRIX.tm426", + "MATRIX.tm431", + "MATRIX.tm432", + "MATRIX.tm433", + "MATRIX.tm434", + "MATRIX.tm435", + "MATRIX.tm436", + "MATRIX.tm441", + "MATRIX.tm442", + "MATRIX.tm443", + "MATRIX.tm444", + "MATRIX.tm445", + "MATRIX.tm446", + "MATRIX.tm451", + "MATRIX.tm452", + "MATRIX.tm453", + "MATRIX.tm454", + "MATRIX.tm455", + "MATRIX.tm456", + "MATRIX.tm461", + "MATRIX.tm462", + "MATRIX.tm463", + "MATRIX.tm464", + "MATRIX.tm465", + "MATRIX.tm466", + "MATRIX.tm511", + "MATRIX.tm512", + "MATRIX.tm513", + "MATRIX.tm514", + "MATRIX.tm515", + "MATRIX.tm516", + "MATRIX.tm521", + "MATRIX.tm522", + "MATRIX.tm523", + "MATRIX.tm524", + "MATRIX.tm525", + "MATRIX.tm526", + "MATRIX.tm531", + "MATRIX.tm532", + "MATRIX.tm533", + "MATRIX.tm534", + "MATRIX.tm535", + "MATRIX.tm536", + "MATRIX.tm541", + "MATRIX.tm542", + "MATRIX.tm543", + "MATRIX.tm544", + "MATRIX.tm545", + "MATRIX.tm546", + "MATRIX.tm551", + "MATRIX.tm552", + "MATRIX.tm553", + "MATRIX.tm554", + "MATRIX.tm555", + "MATRIX.tm556", + "MATRIX.tm561", + "MATRIX.tm562", + "MATRIX.tm563", + "MATRIX.tm564", + "MATRIX.tm565", + "MATRIX.tm566", + "MATRIX.tm611", + "MATRIX.tm612", + "MATRIX.tm613", + "MATRIX.tm614", + "MATRIX.tm615", + "MATRIX.tm616", + "MATRIX.tm621", + "MATRIX.tm622", + "MATRIX.tm623", + "MATRIX.tm624", + "MATRIX.tm625", + "MATRIX.tm626", + "MATRIX.tm631", + "MATRIX.tm632", + "MATRIX.tm633", + "MATRIX.tm634", + "MATRIX.tm635", + "MATRIX.tm636", + "MATRIX.tm641", + "MATRIX.tm642", + "MATRIX.tm643", + "MATRIX.tm644", + "MATRIX.tm645", + "MATRIX.tm646", + "MATRIX.tm651", + "MATRIX.tm652", + "MATRIX.tm653", + "MATRIX.tm654", + "MATRIX.tm655", + "MATRIX.tm656", + "MATRIX.tm661", + "MATRIX.tm662", + "MATRIX.tm663", + "MATRIX.tm664", + "MATRIX.tm665" + ] + } + } + ], + "title": "MATRIX" + }, + "_NAME": "MATRIX" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MONITOR.name", + "MONITOR.l", + "MONITOR.apertype", + "MONITOR.aperture", + "MONITOR.aper_offset", + "MONITOR.aper_tol" + ] + } + } + ], + "title": "MONITOR" + }, + "_NAME": "MONITOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MULTIPOLE.name", + "MULTIPOLE.lrad", + "MULTIPOLE.tilt", + "MULTIPOLE.knl", + "MULTIPOLE.ksl", + "MULTIPOLE.apertype", + "MULTIPOLE.aperture", + "MULTIPOLE.aper_offset", + "MULTIPOLE.aper_tol" + ] + } + } + ], + "title": "MULTIPOLE" + }, + "_NAME": "MULTIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "NLLENS.name", + "NLLENS.knll", + "NLLENS.cnll", + "NLLENS.apertype", + "NLLENS.aperture", + "NLLENS.aper_offset", + "NLLENS.aper_tol" + ] + } + } + ], + "title": "NLLENS" + }, + "_NAME": "NLLENS" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "OCTUPOLE.name", + "OCTUPOLE.l", + "OCTUPOLE.k3", + "OCTUPOLE.k3s", + "OCTUPOLE.tilt", + "OCTUPOLE.apertype", + "OCTUPOLE.aperture", + "OCTUPOLE.aper_offset", + "OCTUPOLE.aper_tol" + ] + } + } + ], + "title": "OCTUPOLE" + }, + "_NAME": "OCTUPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "PLACEHOLDER.name", + "PLACEHOLDER.l", + "PLACEHOLDER.apertype", + "PLACEHOLDER.aperture", + "PLACEHOLDER.aper_offset", + "PLACEHOLDER.aper_tol" + ] + } + } + ], + "title": "PLACEHOLDER" + }, + "_NAME": "PLACEHOLDER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "QUADRUPOLE.name", + "QUADRUPOLE.l", + "QUADRUPOLE.k1", + "QUADRUPOLE.k1s", + "QUADRUPOLE.tilt", + "QUADRUPOLE.thick", + "QUADRUPOLE.apertype", + "QUADRUPOLE.aperture", + "QUADRUPOLE.aper_offset", + "QUADRUPOLE.aper_tol" + ] + } + } + ], + "title": "QUADRUPOLE" + }, + "_NAME": "QUADRUPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RBEND.name", + "RBEND.l", + "RBEND.angle", + "RBEND.tilt", + "RBEND.k1", + "RBEND.k2", + "RBEND.e1", + "RBEND.e2", + "RBEND.fint", + "RBEND.fintx", + "RBEND.hgap", + "RBEND.h1", + "RBEND.h2", + "RBEND.add_angle", + "RBEND.thick", + "RBEND.apertype", + "RBEND.aperture", + "RBEND.aper_offset", + "RBEND.aper_tol" + ] + } + } + ], + "title": "RBEND" + }, + "_NAME": "RBEND" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RCOLLIMATOR.name", + "RCOLLIMATOR.l", + "RCOLLIMATOR.xsize", + "RCOLLIMATOR.ysize", + "RCOLLIMATOR.apertype", + "RCOLLIMATOR.aperture", + "RCOLLIMATOR.aper_offset", + "RCOLLIMATOR.aper_tol" + ] + } + } + ], + "title": "RCOLLIMATOR" + }, + "_NAME": "RCOLLIMATOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFCAVITY.name", + "RFCAVITY.l", + "RFCAVITY.volt", + "RFCAVITY.lag", + "RFCAVITY.harmon", + "RFCAVITY.freq", + "RFCAVITY.apertype", + "RFCAVITY.aperture", + "RFCAVITY.aper_offset", + "RFCAVITY.aper_tol" + ] + } + } + ], + "title": "RFCAVITY" + }, + "_NAME": "RFCAVITY" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFMULTIPOLE.name", + "RFMULTIPOLE.volt", + "RFMULTIPOLE.lag", + "RFMULTIPOLE.harmon", + "RFMULTIPOLE.freq", + "RFMULTIPOLE.lrad", + "RFMULTIPOLE.tilt", + "RFMULTIPOLE.knl", + "RFMULTIPOLE.ksl", + "RFMULTIPOLE.pnl", + "RFMULTIPOLE.psl", + "RFMULTIPOLE.apertype", + "RFMULTIPOLE.aperture", + "RFMULTIPOLE.aper_offset", + "RFMULTIPOLE.aper_tol" + ] + } + } + ], + "title": "RFMULTIPOLE" + }, + "_NAME": "RFMULTIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SBEND.name", + "SBEND.l", + "SBEND.angle", + "SBEND.k1", + "SBEND.k2", + "SBEND.e1", + "SBEND.e2", + "SBEND.tilt", + "SBEND.h1", + "SBEND.h2", + "SBEND.hgap", + "SBEND.fint", + "SBEND.fintx", + "SBEND.thick", + "SBEND.apertype", + "SBEND.aperture", + "SBEND.aper_offset", + "SBEND.aper_tol" + ] + } + } + ], + "title": "SBEND" + }, + "_NAME": "SBEND" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SEXTUPOLE.name", + "SEXTUPOLE.l", + "SEXTUPOLE.k2", + "SEXTUPOLE.k2s", + "SEXTUPOLE.tilt", + "SEXTUPOLE.apertype", + "SEXTUPOLE.aperture", + "SEXTUPOLE.aper_offset", + "SEXTUPOLE.aper_tol" + ] + } + } + ], + "title": "SEXTUPOLE" + }, + "_NAME": "SEXTUPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SOLENOID.name", + "SOLENOID.l", + "SOLENOID.ks", + "SOLENOID.ksi", + "SOLENOID.apertype", + "SOLENOID.aperture", + "SOLENOID.aper_offset", + "SOLENOID.aper_tol" + ] + } + } + ], + "title": "SOLENOID" + }, + "_NAME": "SOLENOID" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SROTATION.name", + "SROTATION.angle", + "SROTATION.apertype", + "SROTATION.aperture", + "SROTATION.aper_offset", + "SROTATION.aper_tol" + ] + } + } + ], + "title": "SROTATION" + }, + "_NAME": "SROTATION" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TRANSLATION.name", + "TRANSLATION.dx", + "TRANSLATION.dy", + "TRANSLATION.ds" + ] + } + } + ], + "title": "TRANSLATION" + }, + "_NAME": "TRANSLATION" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TWCAVITY.name", + "TWCAVITY.l", + "TWCAVITY.volt", + "TWCAVITY.freq", + "TWCAVITY.lag", + "TWCAVITY.psi", + "TWCAVITY.delta_lag", + "TWCAVITY.apertype", + "TWCAVITY.aperture", + "TWCAVITY.aper_offset", + "TWCAVITY.aper_tol" + ] + } + } + ], + "title": "TWCAVITY" + }, + "_NAME": "TWCAVITY" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VACDIPOLE.name", + "VACDIPOLE.l", + "VACDIPOLE.volt", + "VACDIPOLE.freq", + "VACDIPOLE.lag", + "VACDIPOLE.ramp1", + "VACDIPOLE.ramp2", + "VACDIPOLE.ramp3", + "VACDIPOLE.ramp4", + "VACDIPOLE.apertype", + "VACDIPOLE.aperture", + "VACDIPOLE.aper_offset", + "VACDIPOLE.aper_tol" + ] + } + } + ], + "title": "VACDIPOLE" + }, + "_NAME": "VACDIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VKICKER.name", + "VKICKER.l", + "VKICKER.kick", + "VKICKER.tilt", + "VKICKER.apertype", + "VKICKER.aperture", + "VKICKER.aper_offset", + "VKICKER.aper_tol" + ] + } + } + ], + "title": "VKICKER" + }, + "_NAME": "VKICKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VMONITOR.name", + "VMONITOR.l", + "VMONITOR.apertype", + "VMONITOR.aperture", + "VMONITOR.aper_offset", + "VMONITOR.aper_tol" + ] + } + } + ], + "title": "VMONITOR" + }, + "_NAME": "VMONITOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "XROTATION.name", + "XROTATION.angle", + "XROTATION.apertype", + "XROTATION.aperture", + "XROTATION.aper_offset", + "XROTATION.aper_tol" + ] + } + } + ], + "title": "XROTATION" + }, + "_NAME": "XROTATION" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "YROTATION.name", + "YROTATION.angle", + "YROTATION.apertype", + "YROTATION.aperture", + "YROTATION.aper_offset", + "YROTATION.aper_tol" + ] + } + } + ], + "title": "YROTATION" + }, + "_NAME": "YROTATION" + } + ] +} From eca0cd6be63399a66d06b31d8a9f9ace0c2234ff Mon Sep 17 00:00:00 2001 From: garsuga Date: Mon, 24 Apr 2023 20:21:13 +0000 Subject: [PATCH 32/68] organize madx schema --- .../static/react-json/madx-schema.json | 574 ++++++++++-------- 1 file changed, 334 insertions(+), 240 deletions(-) diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 5e552b89e0..fdf93bab4b 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -6360,6 +6360,339 @@ } }, "view": [ + { + "layout": "navTabs", + "config": { + "tabs": [ + { + "name": "lattic", + "title": "Lattice", + "items": [ + { + "layout": "waterfall", + "config": { + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "padding": ".5em", + "items": [ + + ] + } + } + ] + }, + { + "name": "source", + "title": "Source", + "items": [ + { + "layout": "waterfall", + "config": { + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "padding": ".5em", + "items": [ + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Main", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.particle", + "command_beam.mass", + "command_beam.charge", + "bunch.beamDefinition", + "command_beam.energy", + "command_beam.pc", + "command_beam.gamma", + "command_beam.beta", + "command_beam.brho" + ] + } + } + ] + }, + { + "name": "Distribution", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bunch.matchTwissParameters", + "simulation.visualizationBeamlineId" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "EX [m]", + "description": "The horizontal emittance.", + "fields": [ + "command_beam.ex", + "command_beam.ey" + ] + }, + { + "label": "Horizontal Beta [m]", + "fields": [ + "bunch.betx", + "bunch.bety" + ] + }, + { + "label": "Horizontal Alpha", + "fields": [ + "bunch.alfx", + "bunch.alfy" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.et", + "command_beam.sigt", + "command_beam.sige" + ] + } + } + ] + }, + { + "name": "Position", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Centroid [m]", + "fields": [ + "bunch.x", + "bunch.y" + ] + }, + { + "label": "Horizontal Canonical Momentum of $p_x$", + "fields": [ + "bunch.px", + "bunch.py" + ] + } + ] + } + } + ] + }, + { + "name": "Particle Count", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bunch.numberOfParticles", + "bunch.randomSeed" + ] + } + } + ] + } + ] + } + } + ], + "advanced": [], + "title": "Bunch" + }, + "_NAME": "bunch" + } + ] + } + } + ] + }, + { + "name": "control", + "title": "Control", + "items": [ + { + "layout": "waterfall", + "config": { + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "padding": ".5em", + "items": [ + + ] + } + } + ] + }, + { + "name": "visualization", + "title": "Visualization", + "items": [ + { + "layout": "waterfall", + "config": { + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "padding": ".5em", + "items": [ + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.visualizationBeamlineId", + "bunch.numberOfParticles", + "simulation.computeTwissFromParticles" + ] + } + } + ], + "advanced": [], + "title": "Simulation Settings" + }, + "_NAME": "simulationSettings" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.y1", + "twissFromParticlesAnimation.y2", + "twissFromParticlesAnimation.y3" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.includeLattice", + "twissFromParticlesAnimation.notes" + ] + } + } + ], + "title": "Twiss From Particles" + }, + "_NAME": "twissFromParticlesAnimation" + } + ] + } + } + ] + } + ] + } + }, { "layout": "panel", "config": { @@ -6394,145 +6727,7 @@ }, "_NAME": "beamlineReport" }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Main", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_beam.particle", - "command_beam.mass", - "command_beam.charge", - "bunch.beamDefinition", - "command_beam.energy", - "command_beam.pc", - "command_beam.gamma", - "command_beam.beta", - "command_beam.brho" - ] - } - } - ] - }, - { - "name": "Distribution", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "bunch.matchTwissParameters", - "simulation.visualizationBeamlineId" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "EX [m]", - "description": "The horizontal emittance.", - "fields": [ - "command_beam.ex", - "command_beam.ey" - ] - }, - { - "label": "Horizontal Beta [m]", - "fields": [ - "bunch.betx", - "bunch.bety" - ] - }, - { - "label": "Horizontal Alpha", - "fields": [ - "bunch.alfx", - "bunch.alfy" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "command_beam.et", - "command_beam.sigt", - "command_beam.sige" - ] - } - } - ] - }, - { - "name": "Position", - "items": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Centroid [m]", - "fields": [ - "bunch.x", - "bunch.y" - ] - }, - { - "label": "Horizontal Canonical Momentum of $p_x$", - "fields": [ - "bunch.px", - "bunch.py" - ] - } - ] - } - } - ] - }, - { - "name": "Particle Count", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "bunch.numberOfParticles", - "bunch.randomSeed" - ] - } - } - ] - } - ] - } - } - ], - "advanced": [], - "title": "Bunch" - }, - "_NAME": "bunch" - }, + { "layout": "panel", "config": { @@ -7582,34 +7777,6 @@ }, "_NAME": "command_vary" }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.visualizationBeamlineId", - "bunch.numberOfParticles", - "simulation.computeTwissFromParticles" - ] - } - } - ], - "advanced": [], - "title": "Simulation Settings" - }, - "_NAME": "simulationSettings" - }, - { - "layout": "panel", - "config": { - "advanced": [], - "title": "Simulation Status" - }, - "_NAME": "simulationStatus" - }, { "layout": "panel", "config": { @@ -7627,79 +7794,6 @@ }, "_NAME": "twissEllipseReport" }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.x" - ] - } - } - ] - } - }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.y1", - "twissFromParticlesAnimation.y2", - "twissFromParticlesAnimation.y3" - ] - } - } - ] - } - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.includeLattice", - "twissFromParticlesAnimation.notes" - ] - } - } - ], - "title": "Twiss From Particles" - }, - "_NAME": "twissFromParticlesAnimation" - }, { "layout": "panel", "config": { From 0bed6e551ea5ae77a02e5592466e0ddfbee8f00c Mon Sep 17 00:00:00 2001 From: garsuga Date: Mon, 24 Apr 2023 20:30:34 +0000 Subject: [PATCH 33/68] namespace shadow beamline elements --- react/src/layout/layouts.ts | 8 +-- react/src/layout/{ => shadow}/beamline.scss | 0 react/src/layout/{ => shadow}/beamline.tsx | 56 +++++++++---------- .../shadow/beamlineWatchpointReports.tsx | 12 ++-- .../static/react-json/shadow-schema.json | 4 +- 5 files changed, 40 insertions(+), 40 deletions(-) rename react/src/layout/{ => shadow}/beamline.scss (100%) rename react/src/layout/{ => shadow}/beamline.tsx (80%) diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index 5f87e2b155..c4e5919a24 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -17,8 +17,8 @@ import { HorizontalStackLayout, VerticalStackLayout } from "./arrange/stack"; import { ColumnLayout } from "./arrange/column"; import { WaterfallLayout } from "./arrange/waterfall"; import { Histogram2dFromApi } from "./report/histogram2d"; -import { BeamlineWatchpointReports } from "./shadow/beamlineWatchpointReports"; -import { BeamlineLayout } from "./beamline"; +import { ShadowBeamlineWatchpointReports } from "./shadow/beamlineWatchpointReports"; +import { ShadowBeamlineLayout } from "./shadow/beamline"; // TODO rename to LayoutsWrapper @@ -45,8 +45,8 @@ class LayoutWrapper { hStack: HorizontalStackLayout, vStack: VerticalStackLayout, waterfall: WaterfallLayout, - beamlineWatchpointReports: BeamlineWatchpointReports, - beamline: LayoutWithFormController(BeamlineLayout) + shadowBeamlineWatchpointReports: ShadowBeamlineWatchpointReports, + shadowBeamline: LayoutWithFormController(ShadowBeamlineLayout) } constructor () { diff --git a/react/src/layout/beamline.scss b/react/src/layout/shadow/beamline.scss similarity index 100% rename from react/src/layout/beamline.scss rename to react/src/layout/shadow/beamline.scss diff --git a/react/src/layout/beamline.tsx b/react/src/layout/shadow/beamline.tsx similarity index 80% rename from react/src/layout/beamline.tsx rename to react/src/layout/shadow/beamline.tsx index e45d5c8a87..2e111070a5 100644 --- a/react/src/layout/beamline.tsx +++ b/react/src/layout/shadow/beamline.tsx @@ -2,38 +2,38 @@ import React, { useContext, useState } from "react"; import { FunctionComponent } from "react"; import { Container, Modal } from "react-bootstrap"; import { useDispatch, useStore } from "react-redux"; -import { formActionFunctions } from "../component/reusable/form"; -import { ViewPanelActionButtons } from "../component/reusable/panel"; -import { ArrayAliases, HandleFactoryWithArrayAliases } from "../data/alias"; -import { CAppWrapper, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; -import { newModelFromSchema, StoreTypes } from "../data/data"; -import { Dependency } from "../data/dependency"; -import { formStateFromModelState, FormStateHandleFactory } from "../data/form"; -import { CHandleFactory } from "../data/handle"; -import { ArrayFieldState } from "../store/common"; -import { FormFieldState, FormModelState } from "../store/formState"; -import { CRouteHelper } from "../utility/route"; -import { Schema, SchemaLayout } from "../utility/schema"; -import { Layout, LayoutProps } from "./layout"; -import { createLayouts } from "./layouts"; +import { formActionFunctions } from "../../component/reusable/form"; +import { ViewPanelActionButtons } from "../../component/reusable/panel"; +import { ArrayAliases, HandleFactoryWithArrayAliases } from "../../data/alias"; +import { CAppWrapper, CSchema, CSimulationInfoPromise } from "../../data/appwrapper"; +import { newModelFromSchema, StoreTypes } from "../../data/data"; +import { Dependency } from "../../data/dependency"; +import { formStateFromModelState, FormStateHandleFactory } from "../../data/form"; +import { CHandleFactory } from "../../data/handle"; +import { ArrayFieldState } from "../../store/common"; +import { FormFieldState, FormModelState } from "../../store/formState"; +import { CRouteHelper } from "../../utility/route"; +import { Schema, SchemaLayout } from "../../utility/schema"; +import { Layout, LayoutProps } from "../layout"; +import { createLayouts } from "../layouts"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; import "./beamline.scss"; -import { useCoupledState } from "../hook/coupling"; +import { useCoupledState } from "../../hook/coupling"; -export type BeamlineElement = { +export type ShadowBeamlineElement = { items: SchemaLayout[], name: string, model: string, icon: string } -export type BeamlineConfig = { +export type ShadowBeamlineConfig = { beamlineDependency: string, - elements: BeamlineElement[] + elements: ShadowBeamlineElement[] } -export function BeamlineThumbnail(props: { name: string, iconSrc: string, onClick?: () => void }) { +export function ShadowBeamlineThumbnail(props: { name: string, iconSrc: string, onClick?: () => void }) { return (
@@ -44,7 +44,7 @@ export function BeamlineThumbnail(props: { name: string, iconSrc: string, onClic ) } -export function BeamlineItem(props: { index: number, baseElement: BeamlineElement & { layouts: Layout[] }, header: string, aliases: ArrayAliases, onClick?: () => void, onDeleteClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { +export function ShadowBeamlineItem(props: { index: number, baseElement: ShadowBeamlineElement & { layouts: Layout[] }, header: string, aliases: ArrayAliases, onClick?: () => void, onDeleteClick?: () => void, modalShown: boolean, onHideModal?: () => void }) { let { index, baseElement, aliases, onClick, onDeleteClick, modalShown, onHideModal, header } = props; let routeHelper = useContext(CRouteHelper); @@ -93,7 +93,7 @@ export function BeamlineItem(props: { index: number, baseElement: BeamlineElemen
- +
@@ -119,10 +119,10 @@ export function BeamlineItem(props: { index: number, baseElement: BeamlineElemen ) } -export class BeamlineLayout extends Layout { - private elements: (BeamlineElement & {layouts: Layout[]})[]; +export class ShadowBeamlineLayout extends Layout { + private elements: (ShadowBeamlineElement & {layouts: Layout[]})[]; - constructor(config: BeamlineConfig) { + constructor(config: ShadowBeamlineConfig) { super(config); this.elements = config.elements.map(e => createLayouts(e, "items")); } @@ -134,7 +134,7 @@ export class BeamlineLayout extends Layout { let schema = useContext(CSchema); let dispatch = useDispatch(); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; - formHandleFactory.useUpdates(BeamlineLayout); + formHandleFactory.useUpdates(ShadowBeamlineLayout); let appWrapper = useContext(CAppWrapper); let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); @@ -143,7 +143,7 @@ export class BeamlineLayout extends Layout { let handle = formHandleFactory.createHandle>>(beamlineDependency, StoreTypes.FormState).hook(); // TODO: form or model? - let addBeamlineElement = (element: BeamlineElement) => { + let addBeamlineElement = (element: ShadowBeamlineElement) => { let ms = schema.models[element.model]; let nextId = handle.value.value.reduce((prev, cur) => Math.max(prev, parseInt(cur.item.id.value) + 1), 1); let nextPos = handle.value.value.reduce((prev, cur) => Math.max(prev, parseFloat(cur.item.position.value) + 5), 0); @@ -177,7 +177,7 @@ export class BeamlineLayout extends Layout { let elementThumbnails = this.elements.map((e, i) => { return ( - addBeamlineElement(e)} key={i} name={e.name} iconSrc={routeHelper.globalRoute("svg", { fileName: e.icon })}/> + addBeamlineElement(e)} key={i} name={e.name} iconSrc={routeHelper.globalRoute("svg", { fileName: e.icon })}/> ) }) @@ -208,7 +208,7 @@ export class BeamlineLayout extends Layout { ]; return ( - updateShownModal(id)} onDeleteClick={() => removeBeamlineElement(i)} modalShown={shownModal === id} onHideModal={() => shownModal === id && updateShownModal(undefined)}/> + updateShownModal(id)} onDeleteClick={() => removeBeamlineElement(i)} modalShown={shownModal === id} onHideModal={() => shownModal === id && updateShownModal(undefined)}/> ) }) diff --git a/react/src/layout/shadow/beamlineWatchpointReports.tsx b/react/src/layout/shadow/beamlineWatchpointReports.tsx index de41c1a64c..d0e625fe44 100644 --- a/react/src/layout/shadow/beamlineWatchpointReports.tsx +++ b/react/src/layout/shadow/beamlineWatchpointReports.tsx @@ -12,12 +12,12 @@ import { ModelState } from "../../store/models"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; -export type BeamlineWatchpointReportsConfig = { +export type ShadowWatchpointReportsConfig = { beamlineDependency: string, watchpointReportsDependency: string } -function BeamlineWatchpointItem(props: {beamlineIndex: number, aliases: ArrayAliases, overrides: HandleFactoryOverrides, child: Layout} & {[key: string]: any}) { +function ShadowBeamlineWatchpointItem(props: {beamlineIndex: number, aliases: ArrayAliases, overrides: HandleFactoryOverrides, child: Layout} & {[key: string]: any}) { let { aliases, overrides, child, beamlineIndex } = props; let handleFactory = useContext(CHandleFactory); let schema = useContext(CSchema); @@ -32,7 +32,7 @@ function BeamlineWatchpointItem(props: {beamlineIndex: number, aliases: ArrayAli return <> } - aliasedHandleFactory.useUpdates(BeamlineWatchpointItem) + aliasedHandleFactory.useUpdates(ShadowBeamlineWatchpointItem) let Comp = child.component; return ( @@ -41,10 +41,10 @@ function BeamlineWatchpointItem(props: {beamlineIndex: number, aliases: ArrayAli ) } -export class BeamlineWatchpointReports extends Layout { +export class ShadowBeamlineWatchpointReports extends Layout { private reportLayout: Layout; - constructor(config: BeamlineWatchpointReportsConfig) { + constructor(config: ShadowWatchpointReportsConfig) { super(config); this.reportLayout = LAYOUTS.getLayoutForSchema(createPanelConfig(new Dependency("iteration.index"), new Dependency("beamlineElement.position"), new Dependency("beamlineElement.id"))) @@ -96,7 +96,7 @@ export class BeamlineWatchpointReports extends Layout + ) }) diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index fa37fab0c8..fb71988b0a 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -4249,7 +4249,7 @@ "config": { "items": [ { - "layout": "beamline", + "layout": "shadowBeamline", "config": { "beamlineDependency": "beamline.elements", "elements": [ @@ -5155,7 +5155,7 @@ "_NAME": "initialIntensityReport" }, { - "layout": "beamlineWatchpointReports", + "layout": "shadowBeamlineWatchpointReports", "config": { "beamlineDependency": "beamline.elements", "watchpointReportsDependency": "watchpointReports.reports" From 5fd66a42131c58af9377bd2cc639a820da59028a Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 25 Apr 2023 23:18:02 +0000 Subject: [PATCH 34/68] wip implement missing types --- react/src/layout/input/array.tsx | 46 +++++++++-- react/src/layout/madx/beamlineElements.tsx | 20 +++++ react/src/utility/schema.ts | 2 + sirepo/feature_config.py | 2 +- .../static/react-json/madx-schema.json | 77 ++++++++++++++++++- 5 files changed, 137 insertions(+), 10 deletions(-) create mode 100644 react/src/layout/madx/beamlineElements.tsx diff --git a/react/src/layout/input/array.tsx b/react/src/layout/input/array.tsx index f8ff56e901..c02c636d02 100644 --- a/react/src/layout/input/array.tsx +++ b/react/src/layout/input/array.tsx @@ -1,20 +1,50 @@ -import { InputConfigBase, InputLayout } from "./input"; +import { FunctionComponent } from "react"; +import { Schema } from "../../utility/schema"; +import { InputConfigBase, InputLayout, InputComponentProps } from "./input"; export type ArrayInputConfig = { - + itemType: string, + itemCount?: number, + exportAsString: boolean } & InputConfigBase // TODO: garsuga, implement -export class ArrayInputLayout extends InputLayout { - toModelValue: (value: any[]) => any[] = (value) => { - return value; +export class ArrayInputLayout extends InputLayout { + + constructor(config: ArrayInputConfig, schema: Schema) { + super(config); + + let baseType = schema.types[config.itemType]; + if(!baseType) { + throw new Error(`could not find base type=${config.itemType} for arraylike input`) + } + + } - fromModelValue: (value: any[]) => any[] = (value) => { - return value; + toModelValue: (value: V) => M = (value) => { + + } + + fromModelValue: (value: M) => V = (value) => { + }; - validate: (value: any[]) => boolean = (value) => { + validate: (value: V) => boolean = (value) => { return true; }; + + component: FunctionComponent> = (props) => { + + } +} + + +export function LayoutForArrayLike(name: string, schema: Schema) { + let p = /(\w+?)(\d+)?(String)?(Array)/g; + let [_, type, count, isString, isArray] = p.exec(name); + if(isArray !== undefined) { + + } + return undefined; } diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx new file mode 100644 index 0000000000..b1cb3519e1 --- /dev/null +++ b/react/src/layout/madx/beamlineElements.tsx @@ -0,0 +1,20 @@ +import { Layout } from "../layout"; + +export type MadxBeamlineElementsConfig = { + beamlinesDependency: string, + elementsDependency: string, + elementsTemplates: { + group: string, + type: string, + name: string, + items: SchemaLayoutJson[] + }[] +} + +export class MadxBeamlineElementsLayout extends Layout { + constructor(config: MadxBeamlineElementsConfig) { + super(config); + } + + +} diff --git a/react/src/utility/schema.ts b/react/src/utility/schema.ts index 5b35c76234..792251d866 100644 --- a/react/src/utility/schema.ts +++ b/react/src/utility/schema.ts @@ -76,6 +76,7 @@ export type Schema = { constants: {[key: string]: any}, models: SchemaModels, views: SchemaLayout[], + types: {[key: string]: InputLayout}, route: SchemaRoutes, reactRoute: SchemaRoutes, middleware: SchemaMiddleware[] @@ -190,6 +191,7 @@ export function compileSchemaFromJson(schemaObj: SchemaJson): Schema { constants: schemaObj.constants, views: schemaObj.view, models, + types, route: schemaObj.route, reactRoute: schemaObj.reactRoute, middleware: schemaObj.middleware diff --git a/sirepo/feature_config.py b/sirepo/feature_config.py index e9a5c38014..1ab368603c 100644 --- a/sirepo/feature_config.py +++ b/sirepo/feature_config.py @@ -179,7 +179,7 @@ def _test(msg): ), # TODO(pjm): myapp can't be in react_sim_types or unit tests fail react_sim_types=( - ("jspec", "genesis", "warppba", "omega", "myapp", "shadow") + ("jspec", "genesis", "warppba", "omega", "myapp", "shadow", "madx") if pkconfig.channel_in("dev") else (), set, diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index fdf93bab4b..2fc15a008d 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -102,7 +102,82 @@ "defaultValue": "" } }, - "bunchReport": { + "bunchReport1": { + "x": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "y": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "histogramBins": { + "displayName": "Histogram Bins", + "type": "Integer", + "defaultValue": 200 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "afmhot" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "bunchReport2": { + "x": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "y": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "histogramBins": { + "displayName": "Histogram Bins", + "type": "Integer", + "defaultValue": 200 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "afmhot" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "bunchReport3": { + "x": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "y": { + "displayName": "Phase Space Coordinate", + "type": "PhaseSpaceCoordinate" + }, + "histogramBins": { + "displayName": "Histogram Bins", + "type": "Integer", + "defaultValue": 200 + }, + "colorMap": { + "displayName": "Color Map", + "type": "ColorMap", + "defaultValue": "afmhot" + }, + "notes": { + "displayName": "Notes", + "type": "Text", + "defaultValue": "" + } + }, + "bunchReport4": { "x": { "displayName": "Phase Space Coordinate", "type": "PhaseSpaceCoordinate" From 17d39fa3d15c71d6b14148b55ff3006b76a102ca Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 26 Apr 2023 22:23:34 +0000 Subject: [PATCH 35/68] add missing types and convert schema models to new arrays --- react/src/layout/input/array.tsx | 117 ++++++++++++++---- react/src/layout/input/enum.tsx | 68 +++++++++- react/src/layout/input/inputs.ts | 10 +- react/src/layout/input/valueList.tsx | 17 +++ react/src/utility/schema.ts | 10 +- .../static/react-json/common-schema.json | 30 +++++ .../static/react-json/madx-schema.json | 63 +++++++++- 7 files changed, 288 insertions(+), 27 deletions(-) create mode 100644 react/src/layout/input/valueList.tsx diff --git a/react/src/layout/input/array.tsx b/react/src/layout/input/array.tsx index c02c636d02..3661afd909 100644 --- a/react/src/layout/input/array.tsx +++ b/react/src/layout/input/array.tsx @@ -1,50 +1,123 @@ -import { FunctionComponent } from "react"; -import { Schema } from "../../utility/schema"; +import { range } from "lodash"; +import React, { ChangeEventHandler, FunctionComponent } from "react"; +import { Form } from "react-bootstrap"; import { InputConfigBase, InputLayout, InputComponentProps } from "./input"; export type ArrayInputConfig = { - itemType: string, - itemCount?: number, - exportAsString: boolean + } & InputConfigBase // TODO: garsuga, implement -export class ArrayInputLayout extends InputLayout { +export class ArrayInputLayout extends InputLayout { - constructor(config: ArrayInputConfig, schema: Schema) { + constructor(config: ArrayInputConfig) { super(config); + } - let baseType = schema.types[config.itemType]; - if(!baseType) { - throw new Error(`could not find base type=${config.itemType} for arraylike input`) + toModelValue: (value: any[]) => any[] = (value) => { + return value; + } + + fromModelValue: (value: any[]) => any[] = (value) => { + return value; + }; + + validate: (value: any[]) => boolean = (value) => { + return true; + }; +} + + +export type ArrayLikeMultiInputConfig = { + length: number, + baseType: InputLayout, +} & InputConfigBase +export class ArrayLikeMultiInputLayout extends InputLayout { + toModelValue: (value: string[]) => string = (value) => { + return (value || []).join(", "); + }; + + fromModelValue: (value: string) => string[] = (value) => { + return value?.split(",")?.map(s => s.trim()); + }; + + validate: (value: string[]) => boolean = (value) => { + return !(value.map(v => this.config.baseType.validate(v)).includes(false)); + }; + + component: FunctionComponent> = (props) => { + let onChange: (index: number) => (value: any) => void = (index: number) => (value) => { + let nv = [...props.value]; + nv[index] = this.config.baseType.toModelValue(value); + props.onChange(nv); } + let Comp = this.config.baseType.component; + return ( +
+ { + range(0, this.config.length).map(idx => { + let v = props.value && props.value.length > idx ? props.value[idx] : undefined; + return ( + + ) + }) + } +
+ ) } +} - toModelValue: (value: V) => M = (value) => { - - } +export type ArrayLikeInputConfig = { + baseType: InputLayout +} & InputConfigBase +export class ArrayLikeInputLayout extends InputLayout { + toModelValue: (value: string) => string = (value) => { + return value; + }; - fromModelValue: (value: M) => V = (value) => { - + fromModelValue: (value: string) => string = (value) => { + return value; }; - validate: (value: V) => boolean = (value) => { - return true; + validate: (value: string) => boolean = (value) => { + let vals = (value || "").split(" "); + return !(vals.map(e => this.config.baseType.validate(e)).includes(false)) }; - component: FunctionComponent> = (props) => { - + component: FunctionComponent> = (props) => { + let onChange: ChangeEventHandler = (event) => { + props.onChange(event.target.value); + } + return } } -export function LayoutForArrayLike(name: string, schema: Schema) { - let p = /(\w+?)(\d+)?(String)?(Array)/g; - let [_, type, count, isString, isArray] = p.exec(name); +export function layoutForArrayLike(name: string, typeLookupCallback: (name: string) => InputLayout): InputLayout | undefined { + let r = (/(\w+?)(\d+)?(String)?(Array)/g).exec(name); + if(r === null || r === undefined) { + return undefined; + } + let [_, type, count, isString, isArray] = r; if(isArray !== undefined) { + let baseType = typeLookupCallback(type); + if(!baseType) { + throw new Error(`could not find base type=${type} for arraylike input`) + } + if(count !== undefined) { + return new ArrayLikeMultiInputLayout({ + baseType, + length: parseInt(count), + isRequired: true + }); + } + return new ArrayLikeInputLayout({ + baseType, + isRequired: true + }); } return undefined; } diff --git a/react/src/layout/input/enum.tsx b/react/src/layout/input/enum.tsx index b5ad95bd1f..674c1901eb 100644 --- a/react/src/layout/input/enum.tsx +++ b/react/src/layout/input/enum.tsx @@ -8,7 +8,7 @@ import { InputComponentProps, InputConfigBase, InputLayout } from "./input"; import { LayoutProps } from "../layout"; import { pollStatefulCompute } from "../../utility/compute"; import { CHandleFactory } from "../../data/handle"; -import { getValueSelector, StoreTypes } from "../../data/data"; +import { getValueSelector, StoreType, StoreTypes } from "../../data/data"; export type EnumAllowedValues = { value: string, displayName: string }[] @@ -50,6 +50,72 @@ abstract class EnumInputBaseLayout extends InputLayo } } +export type ArrayElementEnumInputConfig = { + arrayDependency: string, + valueFieldName: string, + displayFieldName?: string +} & InputConfigBase + +type ArrayElementEnumOptions = { + value: string, + display: string +}[] + +export class ArrayElementEnumInputLayout extends InputLayout { + + private lastOptionValues: ArrayElementEnumOptions = undefined; + + constructor(config: ArrayElementEnumInputConfig) { + super(config); + } + + toModelValue: (value: string) => string = (v) => v; + fromModelValue: (value: string) => string = (v) => v; + validate: (value: string) => boolean = (value) => { + if(this.lastOptionValues === undefined) { + return true; + } + + return this.lastOptionValues.filter(ov => { + if(!!!ov.value) { + return !!!value; + } + + return ov.value == value + }).length > 0; + }; + + component: FunctionComponent> = (props) => { + let handleFactory = useContext(CHandleFactory); + let depHandle = handleFactory.createHandle(new Dependency(this.config.arrayDependency), StoreTypes.Models).hook(); + + let optionValues = ((depHandle.value || []) as any[]).map(rv => { + return { + display: `${rv[this.config.displayFieldName || this.config.valueFieldName]}`, + value: `${rv[this.config.valueFieldName]}` + } + }) + + if(!this.config.isRequired) { + optionValues = [{ value: undefined, display: "" }, ...optionValues]; + } + + this.lastOptionValues = optionValues; + + const onChange: ChangeEventHandler = event => { + props.onChange(event.target.value); + } + const options = optionValues.map(v => ( + + )); + return + { options } + + } +} + export class EnumInputLayout extends EnumInputBaseLayout { constructor(config: EnumConfigRaw) { super({ diff --git a/react/src/layout/input/inputs.ts b/react/src/layout/input/inputs.ts index a255121bb7..254f9ad8f1 100644 --- a/react/src/layout/input/inputs.ts +++ b/react/src/layout/input/inputs.ts @@ -1,10 +1,11 @@ import { ArrayInputLayout } from "./array"; import { BooleanInputLayout } from "./boolean"; -import { ComputeResultEnumInputLayout, EnumInputLayout, SimulationListEnumInputLayout } from "./enum"; +import { ArrayElementEnumInputLayout, ComputeResultEnumInputLayout, EnumInputLayout, SimulationListEnumInputLayout } from "./enum"; import { FileInputLayout } from "./file"; import { InputLayoutType } from "./input"; import { FloatInputLayout, IntegerInputLayout } from "./number"; import { StringInputLayout } from "./string"; +import { ValueListInputLayout } from "./valueList"; export const TYPE_BASES: {[baseName: string]: InputLayoutType} = { 'Boolean': BooleanInputLayout, @@ -17,5 +18,12 @@ export const TYPE_BASES: {[baseName: string]: InputLayoutType} = { 'SimListEnum': SimulationListEnumInputLayout, // moellep: for omega, replace with real implementation eventually 'SimArray': StringInputLayout, + // garsuga: for madx, replace with real implementation eventually + 'RPNValue': FloatInputLayout, + // garsuga: for madx, replace with real implementation eventually + 'OutputFile': FileInputLayout, + // garsuga: for madx, needs to be implemented + 'ArrayElementEnum': ArrayElementEnumInputLayout, + 'ValueList': ValueListInputLayout, 'Array': ArrayInputLayout } diff --git a/react/src/layout/input/valueList.tsx b/react/src/layout/input/valueList.tsx new file mode 100644 index 0000000000..c389cd967b --- /dev/null +++ b/react/src/layout/input/valueList.tsx @@ -0,0 +1,17 @@ +import React from "react"; +import { FunctionComponent } from "react"; +import { InputComponentProps, InputConfigBase, InputLayout } from "./input"; + +export type ValueListInputConfig = { + +} & InputConfigBase + +export class ValueListInputLayout extends InputLayout { + toModelValue: (value: any) => any = (v) => v; + fromModelValue: (value: any) => any = (v) => v; + validate: (value: any) => boolean = () => true; + + component: FunctionComponent> = (props) => { + return + } +} diff --git a/react/src/utility/schema.ts b/react/src/utility/schema.ts index 792251d866..5d7339dd0b 100644 --- a/react/src/utility/schema.ts +++ b/react/src/utility/schema.ts @@ -1,3 +1,4 @@ +import { layoutForArrayLike } from "../layout/input/array"; import { InputLayout } from "../layout/input/input"; import { TYPE_BASES } from "../layout/input/inputs"; import { mapProperties } from "./object"; @@ -161,12 +162,17 @@ export function compileSchemaFromJson(schemaObj: SchemaJson): Schema { models = mapProperties(schemaObj.model, (modelName, modelObj) => { return mapProperties(modelObj, (fieldName, field): SchemaField => { let { displayName, type: typeName, defaultValue, description, shown, min, max } = field; - let type = types[typeName]; if(!typeName) { throw new Error(`type not defined for model=${modelName} field=${fieldName}`) } + let type = types[typeName]; if(!type) { - missingTypeNames.push(typeName); + let maybeArrayLike = layoutForArrayLike(typeName, (name) => types[name]); + if(maybeArrayLike !== undefined) { + types[typeName] = maybeArrayLike; + } else { + missingTypeNames.push(typeName); + } } return { displayName, diff --git a/sirepo/package_data/static/react-json/common-schema.json b/sirepo/package_data/static/react-json/common-schema.json index 53ed580093..6036be4b78 100644 --- a/sirepo/package_data/static/react-json/common-schema.json +++ b/sirepo/package_data/static/react-json/common-schema.json @@ -126,6 +126,36 @@ "isRequired": false } }, + "OutputFile": { + "base": "OutputFile", + "config": { + "isRequired": false + } + }, + "RPNValue": { + "base": "Float", + "config": { + "isRequired": true + } + }, + "OptionalRPNValue": { + "base": "Float", + "config": { + "isRequired": false + } + }, + "ValidatedString": { + "base": "String", + "config": { + "isRequired": true + } + }, + "ValueList": { + "base": "ValueList", + "config": { + "isRequired": true + } + }, "AspectRatio": { "base": "Enum", "config": { diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 2fc15a008d..3a203642e7 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -4,6 +4,42 @@ "name": { "displayName": "Name", "type": "ValidatedString" + }, + "items": { + "displayName": "Items", + "type": "IdArray" + }, + "id": { + "displayName": "ID", + "type": "Integer" + }, + "angle": { + "displayName": "Angle", + "type": "Float" + }, + "length": { + "displayName": "Length", + "type": "Float" + }, + "distance": { + "displayName": "Distance", + "type": "Float" + }, + "count": { + "displayName": "Count", + "type": "Integer" + } + }, + "lattice": { + "beamlines": { + "displayName": "Beamlines", + "type": "BeamlinesArray" + } + }, + "elements": { + "elements": { + "displayName": "Elements", + "type": "BeamlineElementsArray" } }, "bunch": { @@ -3102,7 +3138,7 @@ }, "l": { "displayName": "L", - "type": "RPNValue [m]", + "type": "RPNValue", "defaultValue": 0, "description": "The collimator length." }, @@ -6171,6 +6207,15 @@ ] } }, + "BeamlinesArray": { + "base": "Array" + }, + "BeamlineElementsArray": { + "base": "Array" + }, + "IdArray": { + "base": "Array" + }, "CommandMakethinStyle": { "base": "Enum", "config": { @@ -6232,6 +6277,22 @@ ] } }, + "LatticeBeamlineList": { + "base": "ArrayElementEnum", + "config": { + "arrayDependency": "lattice.beamlines", + "valueFieldName": "name", + "isRequired": true + } + }, + "OptionalLatticeBeamlineList": { + "base": "ArrayElementEnum", + "config": { + "arrayDependency": "lattice.beamlines", + "valueFieldName": "name", + "isRequired": false + } + }, "ParticleType": { "base": "Enum", "config": { From 47bd8fa8d4b726bc9a15595db4db615563c89bc4 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 26 Apr 2023 22:23:50 +0000 Subject: [PATCH 36/68] change server handling of array types --- sirepo/sim_data/madx.py | 13 +++++++- sirepo/template/code_variable.py | 2 +- sirepo/template/lattice.py | 54 +++++++++++++++++++------------ sirepo/template/madx.py | 46 +++++++++++++++----------- sirepo/template/madx_converter.py | 18 +++++++---- sirepo/template/madx_parser.py | 8 +++-- 6 files changed, 92 insertions(+), 49 deletions(-) diff --git a/sirepo/sim_data/madx.py b/sirepo/sim_data/madx.py index e40e9aeebc..7a5041d6dc 100644 --- a/sirepo/sim_data/madx.py +++ b/sirepo/sim_data/madx.py @@ -25,7 +25,18 @@ def fixup_old_data(cls, data, qcall, **kwargs): ) for container in ("commands", "elements"): for m in dm[container]: + if not isinstance(m, list): + continue cls.update_model_defaults(m, LatticeUtil.model_name_for_data(m)) + if "beamlines" in dm and isinstance(dm.beamlines, list): + dm.lattice = PKDict( + beamlines=list(map(lambda i: PKDict(model="Beamline", item=i), dm.beamlines)) + ) + del dm["beamlines"] + if isinstance(dm.elements, list): + dm.elements = PKDict( + elements=list(map(lambda i: PKDict(model=i.type, item=i), dm.elements)) + ) @classmethod def _compute_job_fields(cls, data, r, compute_model): @@ -39,7 +50,7 @@ def _compute_job_fields(cls, data, r, compute_model): ] if r == "twissReport": res += [ - "beamlines", + "lattice", "elements", "simulation.activeBeamlineId", "rpnVariables", diff --git a/sirepo/template/code_variable.py b/sirepo/template/code_variable.py index 9fbf542cbf..59ad73f839 100644 --- a/sirepo/template/code_variable.py +++ b/sirepo/template/code_variable.py @@ -281,7 +281,7 @@ def __add_beamline_fields(self, data, schema): if not schema.get("model") or not schema.model.get("beamline"): return bs = schema.model.beamline - for bl in data.models.beamlines: + for bl in map(lambda i: i.item, data.models.lattice.beamlines): if "positions" not in bl: continue for f in bs: diff --git a/sirepo/template/lattice.py b/sirepo/template/lattice.py index e368539678..6ec42b4cd2 100644 --- a/sirepo/template/lattice.py +++ b/sirepo/template/lattice.py @@ -171,13 +171,13 @@ def _fix_value(value, names): for v in self.data.models.rpnVariables: if CodeVar.is_var_value(v.value): v.value = _fix_value(v.value, names) - for el in self.data.models.elements: + for el in map(lambda i: i.item, self.data.models.elements.elements): for f in el: v = el[f] if CodeVar.is_var_value(v): el[f] = _fix_value(v, names) for name in names: - for el in self.data.models.elements: + for el in map(lambda i: i.item, self.data.models.elements.elements): if el.name.lower() == names[name][0]: f = names[name][1] if f in el: @@ -202,7 +202,7 @@ def _float_update(model, field): def _compute_drifts(self, code_var): drifts = PKDict() - for el in self.data.models.elements: + for el in map(lambda i: i.item, self.data.models.elements.elements): if el.type == "DRIFT": length = self._format_length(self._eval_var(code_var, el.l)) if length not in drifts: @@ -253,7 +253,10 @@ def _get_drift(self, drifts, length, allow_negative_drift=False): type="DRIFT", ) self.sim_data.update_model_defaults(drift, "DRIFT") - self.data.models.elements.append(drift) + self.data.models.elements.elements.append(PKDict( + model="DRIFT", + item=drift + )) drifts[length] = drift._id return drifts[length] @@ -273,8 +276,8 @@ def _set_default_beamline(self, cmd_type, field1, field2=None): beamline_id = None if name: beamline_id = self.elements_by_name[name].id - elif self.data.models.beamlines: - beamline_id = self.data.models.beamlines[-1].id + elif self.data.models.lattice and self.data.models.lattice.beamlines: + beamline_id = self.data.models.lattice.beamlines[-1].item.id self.data.models.simulation.activeBeamlineId = ( self.data.models.simulation.visualizationBeamlineId ) = beamline_id @@ -327,7 +330,10 @@ def __parse_beamline(self, label, values): label.upper() not in self.elements_by_name ), "duplicate beamline: {}".format(label) self.elements_by_name[label.upper()] = res - self.data.models.beamlines.append(res) + self.data.models.lattice.beamlines.append(PKDict( + item=res, + model="Beamline" + )) def __parse_element(self, cmd, label, values): res = self.__parse_fields( @@ -377,7 +383,10 @@ def __parse_element(self, cmd, label, values): # assert label.upper() not in self.elements_by_name, \ # 'duplicate element labeled: {}'.format(label) self.elements_by_name[label.upper()] = res - self.data.models.elements.append(res) + self.data.models.elements.elements.append(PKDict( + item=res, + model=res.type + )) def __parse_fields(self, cmd, values, res): model_schema = self.schema.model.get(cmd) @@ -659,9 +668,9 @@ def iterate_models(self, iterator, name=None): By default the commands and elements containers are iterated. """ iterator.id_map = self.id_map - names = (name,) if name else ("commands", "elements") - for name in names: - for m in self.data.models[name]: + a = [self.data.models[name]] if name else [map(lambda i: i.item, self.data.models.elements.elements), self.data.models.commands] + for e in a: + for m in e: model_schema = self.schema.model[self.model_name_for_data(m)] iterator.start(m) for k in sorted(m): @@ -673,10 +682,15 @@ def iterate_models(self, iterator, name=None): @classmethod def max_id(cls, data): max_id = 1 - for model_type in "elements", "beamlines", "commands": - if model_type not in data.models: - continue - for m in data.models[model_type]: + a = [] + if "elements" in data.models: + a += map(lambda i: i.item, data.models.elements.elements) + if "lattice" in data.models: + a += map(lambda i: i.item, data.models.lattice.beamlines) + if "commands" in data.models: + a += data.models.commands + for e in a: + for m in e: assert "_id" in m or "id" in m, "Missing id: {}".format(m) i = m._id if "_id" in m else m.id if i > max_id: @@ -746,15 +760,15 @@ def select_beamline(self): beamline_id = sim.activeBeamlineId else: if "visualizationBeamlineId" not in sim or not sim.visualizationBeamlineId: - sim.visualizationBeamlineId = self.data.models.beamlines[0].id + sim.visualizationBeamlineId = self.data.models.lattice.beamlines[0].item.id beamline_id = sim.visualizationBeamlineId return self.id_map[int(beamline_id)] def sort_elements_and_beamlines(self): """Sort elements and beamline models in place, by (type, name) and (name)""" m = self.data.models - m.elements = sorted(m.elements, key=lambda e: (e.type, e.name.lower())) - m.beamlines = sorted(m.beamlines, key=lambda e: e.name.lower()) + m.elements.elements = sorted(m.elements.elements, key=lambda e: (e.item.type, e.item.name.lower())) + m.lattice.beamlines = sorted(m.lattice.beamlines, key=lambda e: e.item.name.lower()) @classmethod def type_for_data(cls, model): @@ -772,9 +786,9 @@ def __add_beamlines(self, beamline, beamlines, ordered_beamlines): def __build_id_map(self, data): """Returns a map of beamlines and elements, (id => model).""" res = {} - for bl in data.models.beamlines: + for bl in map(lambda i: i.item, data.models.lattice.beamlines): res[bl.id] = bl - for el in data.models.elements: + for el in map(lambda i: i.item, data.models.elements.elements): res[el._id] = el if "commands" in data.models: for cmd in data.models.commands: diff --git a/sirepo/template/madx.py b/sirepo/template/madx.py index c0c735bfa0..9a9cceb075 100644 --- a/sirepo/template/madx.py +++ b/sirepo/template/madx.py @@ -247,9 +247,10 @@ def _model(model, name): for k, v in data.models.items(): if k in SCHEMA.model: _model(v, k) - for x in ("elements", "commands"): - for m in data.models[x]: - _model(m, LatticeUtil.model_name_for_data(m)) + for m in data.models["commands"]: + _model(m, LatticeUtil.model_name_for_data(m)) + for m in map(lambda i: i.item, data.models.elements.elements): + _model(m, LatticeUtil.model_name_for_data(m)) def extract_parameter_report( @@ -372,6 +373,7 @@ def post_execution_processing(success_exit, run_dir, **kwargs): def prepare_for_client(data, qcall, **kwargs): + pkdp(data.models.rpnVariables) code_var(data.models.rpnVariables).compute_cache(data, SCHEMA) return data @@ -432,8 +434,9 @@ def to_string(value): def uniquify_elements(data): def _do_unique(elem_ids): - element_map = PKDict({e._id: e for e in data.models.elements}) - names = set([e.name for e in data.models.elements]) + ae = map(lambda i: i.item, data.model.elements.elements) + element_map = PKDict({e._id: e for e in ae}) + names = set([e.name for e in ae]) max_id = LatticeUtil.max_id(data) res = [] for el_id in elem_ids: @@ -444,7 +447,8 @@ def _do_unique(elem_ids): el.name = _unique_name(el.name, names) max_id += 1 el._id = max_id - data.models.elements.append(el) + #data.models.elements.append(el) garsuga: why mutate this when res is returned??? + data.models.elements.elements.append(PKDict(model=el.type, item=el)) res.append(el._id) return res @@ -500,10 +504,10 @@ def _reduce_to_elements_with_reflection(beamline): def _remove_unused_elements(items): res = [] - for el in data.models.elements: - if el._id in items: + for el in data.models.elements.elements: + if el.item._id in items: res.append(el) - data.models.elements = res + data.models.elements.elements = res def _unique_name(name, names): assert name in names @@ -517,12 +521,12 @@ def _unique_name(name, names): names.add(f"{name}{count}") return f"{name}{count}" - beamline_map = PKDict({b.id: b for b in data.models.beamlines}) + beamline_map = PKDict({b.id: b for b in map(lambda i: i.item, data.models.lattice.beamlines)}) b = beamline_map[data.models.simulation.visualizationBeamlineId] _reduce_to_elements_with_reflection(b) _remove_unused_elements(b["items"]) b["items"] = _do_unique(b["items"]) - data.models.beamlines = [b] + data.models.lattice.beamlines = [PKDict(item=b, model="Beamline")] def write_parameters(data, run_dir, is_parallel, filename=MADX_INPUT_FILE): @@ -575,13 +579,13 @@ def _add_commands(data, util): def _add_marker_and_observe(data): def _add_marker(data): assert ( - len(data.models.beamlines) == 1 - ), f"should have only one beamline reduced to elements. beamlines={data.models.beamlines}" - beam = data.models.beamlines[0] + len(data.models.lattice.beamlines) == 1 + ), f"should have only one beamline reduced to elements. beamlines={data.models.lattice.beamlines}" + beam = data.models.lattice.beamlines[0].item markers = PKDict() m = LatticeUtil.max_id(data) el_map = PKDict() - for el in data.models.elements: + for el in map(lambda i: i.item, data.models.elements.elements): el_map[el._id] = el items_copy = beam["items"].copy() bi = 0 @@ -598,12 +602,16 @@ def _add_marker(data): bi += 1 n = f"Marker{m}_{el.type}" markers[m] = n - data.models.elements.append( + data.models.elements.elements.append( PKDict( - _id=m, - name=n, - type="MARKER", + model="MARKER", + item=PKDict( + _id=m, + name=n, + type="MARKER", + ) ) + ) return markers, m diff --git a/sirepo/template/madx_converter.py b/sirepo/template/madx_converter.py index d7931d0f2d..4452a2ea3d 100644 --- a/sirepo/template/madx_converter.py +++ b/sirepo/template/madx_converter.py @@ -108,12 +108,15 @@ def _convert(self, data): return self.result def _copy_beamlines(self, data): - for bl in data.models.beamlines: + for bl in map(lambda i: i.item, data.models.lattice.beamlines): self.result.models.beamlines.append( PKDict( - name=bl.name, - items=bl["items"], - id=bl.id, + item=PKDict( + name=bl.name, + items=bl["items"], + id=bl.id, + ), + model="Beamline" ) ) for f in ("name", "visualizationBeamlineId", "activeBeamlineId"): @@ -137,7 +140,7 @@ def _copy_code_variables(self, data): self.result.models.rpnVariables = res def _copy_elements(self, data): - for el in data.models.elements: + for el in map(lambda i: i.item, data.models.elements.elements): if el.type not in self.field_map: pkdlog("Unhandled element type: {}", el.type) el.type = self.drift_type @@ -158,7 +161,10 @@ def _copy_elements(self, data): values[f1] = el[f2] self._fixup_element(el, values) self.to_class.update_model_defaults(values, values.type) - self.result.models.elements.append(values) + self.result.models.elements.elements.append(PKDict( + item=values, + model=values.type + )) def _find_var(self, data, name): name = self._var_name(name) diff --git a/sirepo/template/madx_parser.py b/sirepo/template/madx_parser.py index 3d4415fe0b..a3ae4d1bc4 100644 --- a/sirepo/template/madx_parser.py +++ b/sirepo/template/madx_parser.py @@ -91,7 +91,8 @@ def __convert_references_to_ids(self): # assert name not in name_to_id, 'duplicate name: {}'.format(name) name_to_id[name] = id for container in ("elements", "commands"): - for el in self.data.models[container]: + dm = map(lambda i: i.item, self.data.models[container].elements) if container == "elements" else self.data.models[container] + for el in dm: model_schema = self.schema.model[ lattice.LatticeUtil.model_name_for_data(el) ] @@ -154,7 +155,10 @@ def __convert_sequences_to_beamlines(self, code_var): if d: beamline["items"].append(d) beamline.id = self.parser.next_id() - data.models.beamlines.append(beamline) + data.models.lattice.beamlines.append(PKDict( + item=beamline, + model="Beamline" + )) del data.models["sequences"] util.sort_elements_and_beamlines() From 8191b3b155b385c36d5ee80edaa09591758e91e5 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 26 Apr 2023 23:49:52 +0000 Subject: [PATCH 37/68] reorganize schema --- react/src/component/reusable/form.tsx | 4 +- .../static/react-json/madx-schema.json | 4647 +++++++++-------- 2 files changed, 2423 insertions(+), 2228 deletions(-) diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index bbb96e8144..939179ecb4 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -92,10 +92,10 @@ export function FormStateInitializer(props) { if(!value) { throw new Error(`could not get model=${modelName}`); } - let modelSchema = schema.models[modelName]; + /*let modelSchema = schema.models[modelName]; if(!modelSchema) { throw new Error(`could not get schema for model=${modelName}`); - } + }*/ dispatch(formActions.updateModel({ name: modelName, value: mapProperties(value, (_, fv) => initialFormStateFromValue(fv)) diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 3a203642e7..9b85f108f6 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -42,6 +42,7 @@ "type": "BeamlineElementsArray" } }, + "commands": {}, "bunch": { "beamDefinition": { "displayName": "Beam Definition", @@ -6680,6 +6681,230 @@ "title": "Bunch" }, "_NAME": "bunch" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport1", + "dependencies": [ + "simulationSettings.*", + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport1.x", + "bunchReport1.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport1.histogramBins", + "bunchReport1.colorMap", + "bunchReport1.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport1" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport2", + "dependencies": [ + "simulationSettings.*", + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport2.x", + "bunchReport2.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport2.histogramBins", + "bunchReport2.colorMap", + "bunchReport2.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport2" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport3", + "dependencies": [ + "simulationSettings.*", + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport3.x", + "bunchReport3.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport3.histogramBins", + "bunchReport3.colorMap", + "bunchReport3.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport3" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport4", + "dependencies": [ + "simulationSettings.*", + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport4.x", + "bunchReport4.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport4.histogramBins", + "bunchReport4.colorMap", + "bunchReport4.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport4" } ] } @@ -6828,7 +7053,9 @@ } ] } - }, + } + ], + "unusedViews": [ { "layout": "panel", "config": { @@ -6846,2304 +7073,2272 @@ }, "_NAME": "beamline" }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "beamlineReport.notes" - ] - } - } - ], - "title": "Lattice" - }, - "_NAME": "beamlineReport" - }, - - { - "layout": "panel", - "config": { - "basic": [], - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Phase Space Coordinate", - "fields": [ - "bunchReport.x", - "bunchReport.y" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "bunchReport.histogramBins", - "bunchReport.colorMap", - "bunchReport.notes" - ] - } - } - ], - "title": "Bunch Report" - }, - "_NAME": "bunchReport" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Value to Plot", - "fields": [ - "elementAnimation.x", - "elementAnimation.y1" - ] - } - ] + [ + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "beamlineReport.notes" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.framesPerSecond", - "elementAnimation.histogramBins", - "elementAnimation.aspectRatio", - "elementAnimation.colorMap", - "elementAnimation.notes" - ] + ], + "title": "Lattice" + }, + "_NAME": "beamlineReport" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Value to Plot", + "fields": [ + "elementAnimation.x", + "elementAnimation.y1" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.framesPerSecond", + "elementAnimation.histogramBins", + "elementAnimation.aspectRatio", + "elementAnimation.colorMap", + "elementAnimation.notes" + ] + } } - } - ], - "title": "Output Report" - }, - "_NAME": "heatmapFrameAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" + ], + "title": "Output Report" + }, + "_NAME": "heatmapFrameAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.x" - ] + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } } - } - ] + ] + } } - }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.framesPerSecond", + "elementAnimation.includeLattice", + "elementAnimation.notes" + ] + } + } + ], + "title": "Output Report" + }, + "_NAME": "plotFrameAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "Match Summary" + }, + "_NAME": "matchSummaryAnimation" + }, + + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "twissEllipseReport.dim" + ] + } + } + ], + "title": "Twiss Ellipse" + }, + "_NAME": "twissEllipseReport" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.y1", - "elementAnimation.y2", - "elementAnimation.y3" - ] + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } } - } - ] + ] + } } - } - ] + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.includeLattice" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.framesPerSecond", - "elementAnimation.includeLattice", - "elementAnimation.notes" - ] + ], + "title": "Twiss Parameters" + }, + "_NAME": "twissAnimation" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "twissReport.y1", + "twissReport.y2", + "twissReport.y3", + "twissReport.includeLattice" + ] + } } - } - ], - "title": "Output Report" - }, - "_NAME": "plotFrameAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [], - "title": "Match Summary" - }, - "_NAME": "matchSummaryAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_beam.particle", - "command_beam.mass", - "command_beam.charge", - "command_beam.energy", - "command_beam.pc", - "command_beam.gamma", - "command_beam.beta", - "command_beam.brho", - "command_beam.ex", - "command_beam.exn", - "command_beam.ey", - "command_beam.eyn", - "command_beam.et", - "command_beam.sequence", - "command_beam.sigt", - "command_beam.sige", - "command_beam.kbunch", - "command_beam.npart", - "command_beam.bcurrent", - "command_beam.bunched", - "command_beam.radiate", - "command_beam.bv" - ] + ], + "title": "Twiss Parameters" + }, + "_NAME": "twissReport" + } + ], + [ + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "BEAMBEAM.name", + "BEAMBEAM.sigx", + "BEAMBEAM.sigy", + "BEAMBEAM.xma", + "BEAMBEAM.yma", + "BEAMBEAM.charge", + "BEAMBEAM.bbshape", + "BEAMBEAM.width", + "BEAMBEAM.bbdir", + "BEAMBEAM.apertype", + "BEAMBEAM.aperture", + "BEAMBEAM.aper_offset", + "BEAMBEAM.aper_tol" + ] + } } - } - ], - "title": "beam" - }, - "_NAME": "command_beam" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_beta0.betx", - "command_beta0.alfx", - "command_beta0.bety", - "command_beta0.mux", - "command_beta0.alfy", - "command_beta0.muy", - "command_beta0.x", - "command_beta0.px", - "command_beta0.y", - "command_beta0.py", - "command_beta0.t", - "command_beta0.pt", - "command_beta0.dx", - "command_beta0.dpx", - "command_beta0.dy", - "command_beta0.dpy", - "command_beta0.wx", - "command_beta0.phix", - "command_beta0.dmux", - "command_beta0.wy", - "command_beta0.phiy", - "command_beta0.dmuy", - "command_beta0.ddx", - "command_beta0.ddpx", - "command_beta0.ddy", - "command_beta0.ddpy", - "command_beta0.r11", - "command_beta0.r12", - "command_beta0.r21", - "command_beta0.r22", - "command_beta0.energy" - ] - } - } - ], - "title": "beta0" - }, - "_NAME": "command_beta0" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_constraint.sequence", - "command_constraint.range", - "command_constraint.alfx", - "command_constraint.alfy", - "command_constraint.betx", - "command_constraint.bety", - "command_constraint.dpx", - "command_constraint.dpy", - "command_constraint.dx", - "command_constraint.dy", - "command_constraint.mux", - "command_constraint.muy", - "command_constraint.px", - "command_constraint.py", - "command_constraint.x", - "command_constraint.y" - ] - } - } - ], - "title": "constraint" - }, - "_NAME": "command_constraint" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ealign.dx", - "command_ealign.dy", - "command_ealign.ds", - "command_ealign.dphi", - "command_ealign.dtheta", - "command_ealign.dpsi", - "command_ealign.mrex", - "command_ealign.mrey", - "command_ealign.mscalx", - "command_ealign.mscaly", - "command_ealign.arex", - "command_ealign.arey" - ] - } - } - ], - "title": "ealign" - }, - "_NAME": "command_ealign" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_emit.deltap", - "command_emit.tol" - ] - } - } - ], - "title": "emit" - }, - "_NAME": "command_emit" - }, - { - "layout": "panel", - "config": { - "advanced": [], - "title": "endmatch" - }, - "_NAME": "command_endmatch" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_global.sequence", - "command_global.q1", - "command_global.q2", - "command_global.dq1", - "command_global.dq2" - ] - } - } - ], - "title": "global" - }, - "_NAME": "command_global" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_jacobian.calls", - "command_jacobian.tolerance", - "command_jacobian.repeat", - "command_jacobian.strategy", - "command_jacobian.cool", - "command_jacobian.balance", - "command_jacobian.random" - ] - } - } - ], - "title": "jacobian" - }, - "_NAME": "command_jacobian" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_lmdif.calls", - "command_lmdif.tolerance" - ] - } - } - ], - "title": "lmdif" - }, - "_NAME": "command_lmdif" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_makethin.sequence", - "command_makethin.style", - "command_makethin.makedipedge" - ] + ], + "title": "BEAMBEAM" + }, + "_NAME": "BEAMBEAM" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CHANGEREF.name", + "CHANGEREF.patch_ang", + "CHANGEREF.patch_trans", + "CHANGEREF.apertype", + "CHANGEREF.aperture", + "CHANGEREF.aper_offset", + "CHANGEREF.aper_tol" + ] + } } - } - ], - "title": "makethin" - }, - "_NAME": "command_makethin" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_match.sequence", - "command_match.alfx", - "command_match.alfy", - "command_match.betx", - "command_match.bety", - "command_match.deltap", - "command_match.dpx", - "command_match.dpy", - "command_match.dx", - "command_match.dy", - "command_match.mux", - "command_match.muy", - "command_match.px", - "command_match.py", - "command_match.x", - "command_match.y" - ] + ], + "title": "CHANGEREF" + }, + "_NAME": "CHANGEREF" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "COLLIMATOR.name", + "COLLIMATOR.l", + "COLLIMATOR.apertype", + "COLLIMATOR.aperture", + "COLLIMATOR.aper_offset", + "COLLIMATOR.aper_tol" + ] + } } - } - ], - "title": "match" - }, - "_NAME": "command_match" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_migrad.calls", - "command_migrad.tolerance", - "command_migrad.strategy" - ] + ], + "title": "COLLIMATOR" + }, + "_NAME": "COLLIMATOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CRABCAVITY.name", + "CRABCAVITY.l", + "CRABCAVITY.volt", + "CRABCAVITY.lag", + "CRABCAVITY.freq", + "CRABCAVITY.rv1", + "CRABCAVITY.rv2", + "CRABCAVITY.rv3", + "CRABCAVITY.rv4", + "CRABCAVITY.rph1", + "CRABCAVITY.rph2", + "CRABCAVITY.lagf", + "CRABCAVITY.apertype", + "CRABCAVITY.aperture", + "CRABCAVITY.aper_offset", + "CRABCAVITY.aper_tol" + ] + } } - } - ], - "title": "migrad" - }, - "_NAME": "command_migrad" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_option.bborbit", - "command_option.debug", - "command_option.echo", - "command_option.echomacro", - "command_option.info", - "command_option.no_fatal_stop", - "command_option.rbarc", - "command_option.reset", - "command_option.sympl", - "command_option.tell", - "command_option.thin_foc", - "command_option.threader", - "command_option.trace", - "command_option.twiss_print", - "command_option.verbose", - "command_option.verify", - "command_option.warn" - ] + ], + "title": "CRABCAVITY" + }, + "_NAME": "CRABCAVITY" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DIPEDGE.name", + "DIPEDGE.h", + "DIPEDGE.e1", + "DIPEDGE.fint", + "DIPEDGE.hgap", + "DIPEDGE.tilt", + "DIPEDGE.apertype", + "DIPEDGE.aperture", + "DIPEDGE.aper_offset", + "DIPEDGE.aper_tol" + ] + } } - } - ], - "title": "option" - }, - "_NAME": "command_option" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_create_layout.time", - "command_ptc_create_layout.model", - "command_ptc_create_layout.method", - "command_ptc_create_layout.nst", - "command_ptc_create_layout.exact", - "command_ptc_create_layout.offset_deltap", - "command_ptc_create_layout.errors_out", - "command_ptc_create_layout.magnet_name", - "command_ptc_create_layout.resplit", - "command_ptc_create_layout.thin", - "command_ptc_create_layout.xbend", - "command_ptc_create_layout.even" - ] + ], + "title": "DIPEDGE" + }, + "_NAME": "DIPEDGE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DRIFT.name", + "DRIFT.l" + ] + } } - } - ], - "title": "ptc_create_layout" - }, - "_NAME": "command_ptc_create_layout" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_create_universe.sector_nmul_max", - "command_ptc_create_universe.sector_nmul", - "command_ptc_create_universe.ntpsa", - "command_ptc_create_universe.symprint" - ] + ], + "title": "DRIFT" + }, + "_NAME": "DRIFT" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "ECOLLIMATOR.name", + "ECOLLIMATOR.l", + "ECOLLIMATOR.xsize", + "ECOLLIMATOR.ysize", + "ECOLLIMATOR.apertype", + "ECOLLIMATOR.aperture", + "ECOLLIMATOR.aper_offset", + "ECOLLIMATOR.aper_tol" + ] + } } - } - ], - "title": "ptc_create_universe" - }, - "_NAME": "command_ptc_create_universe" - }, - { - "layout": "panel", - "config": { - "advanced": [], - "title": "ptc_create_end" - }, - "_NAME": "command_ptc_end" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_normal.closed_orbit", - "command_ptc_normal.deltap", - "command_ptc_normal.icase", - "command_ptc_normal.map_table", - "command_ptc_normal.no", - "command_ptc_normal.normal" - ] + ], + "title": "ECOLLIMATOR" + }, + "_NAME": "ECOLLIMATOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HACDIPOLE.name", + "HACDIPOLE.l", + "HACDIPOLE.volt", + "HACDIPOLE.freq", + "HACDIPOLE.lag", + "HACDIPOLE.ramp1", + "HACDIPOLE.ramp2", + "HACDIPOLE.ramp3", + "HACDIPOLE.ramp4", + "HACDIPOLE.apertype", + "HACDIPOLE.aperture", + "HACDIPOLE.aper_offset", + "HACDIPOLE.aper_tol" + ] + } } - } - ], - "title": "ptc_normal" - }, - "_NAME": "command_ptc_normal" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_observe.place" - ] + ], + "title": "HACDIPOLE" + }, + "_NAME": "HACDIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HKICKER.name", + "HKICKER.l", + "HKICKER.kick", + "HKICKER.tilt", + "HKICKER.apertype", + "HKICKER.aperture", + "HKICKER.aper_offset", + "HKICKER.aper_tol" + ] + } } - } - ], - "title": "ptc_observe" - }, - "_NAME": "command_ptc_observe" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_select.table", - "command_ptc_select.column", - "command_ptc_select.polynomial", - "command_ptc_select.monomial", - "command_ptc_select.parametric", - "command_ptc_select.quantity" - ] + ], + "title": "HKICKER" + }, + "_NAME": "HKICKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HMONITOR.name", + "HMONITOR.l", + "HMONITOR.apertype", + "HMONITOR.aperture", + "HMONITOR.aper_offset", + "HMONITOR.aper_tol" + ] + } } - } - ], - "title": "ptc_select" - }, - "_NAME": "command_ptc_select" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_setswitch.debuglevel", - "command_ptc_setswitch.exact_mis", - "command_ptc_setswitch.totalpath", - "command_ptc_setswitch.radiation", - "command_ptc_setswitch.envelope", - "command_ptc_setswitch.stochastic", - "command_ptc_setswitch.modulation", - "command_ptc_setswitch.fringe" - ] + ], + "title": "HMONITOR" + }, + "_NAME": "HMONITOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "INSTRUMENT.name", + "INSTRUMENT.l", + "INSTRUMENT.apertype", + "INSTRUMENT.aperture", + "INSTRUMENT.aper_offset", + "INSTRUMENT.aper_tol" + ] + } } - } - ], - "title": "ptc_setswitch" - }, - "_NAME": "command_ptc_setswitch" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_start.x", - "command_ptc_start.px", - "command_ptc_start.y", - "command_ptc_start.py", - "command_ptc_start.t", - "command_ptc_start.pt", - "command_ptc_start.fx", - "command_ptc_start.phix", - "command_ptc_start.fy", - "command_ptc_start.phiy", - "command_ptc_start.ft", - "command_ptc_start.phit" - ] + ], + "title": "INSTRUMENT" + }, + "_NAME": "INSTRUMENT" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "KICKER.name", + "KICKER.l", + "KICKER.hkick", + "KICKER.vkick", + "KICKER.tilt", + "KICKER.apertype", + "KICKER.aperture", + "KICKER.aper_offset", + "KICKER.aper_tol" + ] + } } - } - ], - "title": "ptc_start" - }, - "_NAME": "command_ptc_start" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_track.deltap", - "command_ptc_track.icase", - "command_ptc_track.closed_orbit", - "command_ptc_track.element_by_element", - "command_ptc_track.turns", - "command_ptc_track.maxaper", - "command_ptc_track.norm_no", - "command_ptc_track.file", - "command_ptc_track.norm_out", - "command_ptc_track.ffile", - "command_ptc_track.radiation", - "command_ptc_track.radiation_model1", - "command_ptc_track.radiation_energy_loss", - "command_ptc_track.radiation_quad", - "command_ptc_track.beam_envelope", - "command_ptc_track.space_charge" - ] + ], + "title": "KICKER" + }, + "_NAME": "KICKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MARKER.name", + "MARKER.apertype", + "MARKER.aperture", + "MARKER.aper_offset", + "MARKER.aper_tol" + ] + } } - } - ], - "title": "ptc_track" - }, - "_NAME": "command_ptc_track" - }, - { - "layout": "panel", - "config": { - "advanced": [], - "title": "ptc_track_end" - }, - "_NAME": "command_ptc_track_end" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_trackline.turns", - "command_ptc_trackline.file", - "command_ptc_trackline.everystep", - "command_ptc_trackline.gcs" - ] + ], + "title": "MARKER" + }, + "_NAME": "MARKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MATRIX.name", + "MATRIX.l", + "MATRIX.kick1", + "MATRIX.kick6", + "MATRIX.rm11", + "MATRIX.rm66", + "MATRIX.tm111", + "MATRIX.tm666", + "MATRIX.kick2", + "MATRIX.kick3", + "MATRIX.kick4", + "MATRIX.kick5", + "MATRIX.rm12", + "MATRIX.rm13", + "MATRIX.rm14", + "MATRIX.rm15", + "MATRIX.rm16", + "MATRIX.rm21", + "MATRIX.rm22", + "MATRIX.rm23", + "MATRIX.rm24", + "MATRIX.rm25", + "MATRIX.rm26", + "MATRIX.rm31", + "MATRIX.rm32", + "MATRIX.rm33", + "MATRIX.rm34", + "MATRIX.rm35", + "MATRIX.rm36", + "MATRIX.rm41", + "MATRIX.rm42", + "MATRIX.rm43", + "MATRIX.rm44", + "MATRIX.rm45", + "MATRIX.rm46", + "MATRIX.rm51", + "MATRIX.rm52", + "MATRIX.rm53", + "MATRIX.rm54", + "MATRIX.rm55", + "MATRIX.rm56", + "MATRIX.rm61", + "MATRIX.rm62", + "MATRIX.rm63", + "MATRIX.rm64", + "MATRIX.rm65", + "MATRIX.tm112", + "MATRIX.tm113", + "MATRIX.tm114", + "MATRIX.tm115", + "MATRIX.tm116", + "MATRIX.tm121", + "MATRIX.tm122", + "MATRIX.tm123", + "MATRIX.tm124", + "MATRIX.tm125", + "MATRIX.tm126", + "MATRIX.tm131", + "MATRIX.tm132", + "MATRIX.tm133", + "MATRIX.tm134", + "MATRIX.tm135", + "MATRIX.tm136", + "MATRIX.tm141", + "MATRIX.tm142", + "MATRIX.tm143", + "MATRIX.tm144", + "MATRIX.tm145", + "MATRIX.tm146", + "MATRIX.tm151", + "MATRIX.tm152", + "MATRIX.tm153", + "MATRIX.tm154", + "MATRIX.tm155", + "MATRIX.tm156", + "MATRIX.tm161", + "MATRIX.tm162", + "MATRIX.tm163", + "MATRIX.tm164", + "MATRIX.tm165", + "MATRIX.tm166", + "MATRIX.tm211", + "MATRIX.tm212", + "MATRIX.tm213", + "MATRIX.tm214", + "MATRIX.tm215", + "MATRIX.tm216", + "MATRIX.tm221", + "MATRIX.tm222", + "MATRIX.tm223", + "MATRIX.tm224", + "MATRIX.tm225", + "MATRIX.tm226", + "MATRIX.tm231", + "MATRIX.tm232", + "MATRIX.tm233", + "MATRIX.tm234", + "MATRIX.tm235", + "MATRIX.tm236", + "MATRIX.tm241", + "MATRIX.tm242", + "MATRIX.tm243", + "MATRIX.tm244", + "MATRIX.tm245", + "MATRIX.tm246", + "MATRIX.tm251", + "MATRIX.tm252", + "MATRIX.tm253", + "MATRIX.tm254", + "MATRIX.tm255", + "MATRIX.tm256", + "MATRIX.tm261", + "MATRIX.tm262", + "MATRIX.tm263", + "MATRIX.tm264", + "MATRIX.tm265", + "MATRIX.tm266", + "MATRIX.tm311", + "MATRIX.tm312", + "MATRIX.tm313", + "MATRIX.tm314", + "MATRIX.tm315", + "MATRIX.tm316", + "MATRIX.tm321", + "MATRIX.tm322", + "MATRIX.tm323", + "MATRIX.tm324", + "MATRIX.tm325", + "MATRIX.tm326", + "MATRIX.tm331", + "MATRIX.tm332", + "MATRIX.tm333", + "MATRIX.tm334", + "MATRIX.tm335", + "MATRIX.tm336", + "MATRIX.tm341", + "MATRIX.tm342", + "MATRIX.tm343", + "MATRIX.tm344", + "MATRIX.tm345", + "MATRIX.tm346", + "MATRIX.tm351", + "MATRIX.tm352", + "MATRIX.tm353", + "MATRIX.tm354", + "MATRIX.tm355", + "MATRIX.tm356", + "MATRIX.tm361", + "MATRIX.tm362", + "MATRIX.tm363", + "MATRIX.tm364", + "MATRIX.tm365", + "MATRIX.tm366", + "MATRIX.tm411", + "MATRIX.tm412", + "MATRIX.tm413", + "MATRIX.tm414", + "MATRIX.tm415", + "MATRIX.tm416", + "MATRIX.tm421", + "MATRIX.tm422", + "MATRIX.tm423", + "MATRIX.tm424", + "MATRIX.tm425", + "MATRIX.tm426", + "MATRIX.tm431", + "MATRIX.tm432", + "MATRIX.tm433", + "MATRIX.tm434", + "MATRIX.tm435", + "MATRIX.tm436", + "MATRIX.tm441", + "MATRIX.tm442", + "MATRIX.tm443", + "MATRIX.tm444", + "MATRIX.tm445", + "MATRIX.tm446", + "MATRIX.tm451", + "MATRIX.tm452", + "MATRIX.tm453", + "MATRIX.tm454", + "MATRIX.tm455", + "MATRIX.tm456", + "MATRIX.tm461", + "MATRIX.tm462", + "MATRIX.tm463", + "MATRIX.tm464", + "MATRIX.tm465", + "MATRIX.tm466", + "MATRIX.tm511", + "MATRIX.tm512", + "MATRIX.tm513", + "MATRIX.tm514", + "MATRIX.tm515", + "MATRIX.tm516", + "MATRIX.tm521", + "MATRIX.tm522", + "MATRIX.tm523", + "MATRIX.tm524", + "MATRIX.tm525", + "MATRIX.tm526", + "MATRIX.tm531", + "MATRIX.tm532", + "MATRIX.tm533", + "MATRIX.tm534", + "MATRIX.tm535", + "MATRIX.tm536", + "MATRIX.tm541", + "MATRIX.tm542", + "MATRIX.tm543", + "MATRIX.tm544", + "MATRIX.tm545", + "MATRIX.tm546", + "MATRIX.tm551", + "MATRIX.tm552", + "MATRIX.tm553", + "MATRIX.tm554", + "MATRIX.tm555", + "MATRIX.tm556", + "MATRIX.tm561", + "MATRIX.tm562", + "MATRIX.tm563", + "MATRIX.tm564", + "MATRIX.tm565", + "MATRIX.tm566", + "MATRIX.tm611", + "MATRIX.tm612", + "MATRIX.tm613", + "MATRIX.tm614", + "MATRIX.tm615", + "MATRIX.tm616", + "MATRIX.tm621", + "MATRIX.tm622", + "MATRIX.tm623", + "MATRIX.tm624", + "MATRIX.tm625", + "MATRIX.tm626", + "MATRIX.tm631", + "MATRIX.tm632", + "MATRIX.tm633", + "MATRIX.tm634", + "MATRIX.tm635", + "MATRIX.tm636", + "MATRIX.tm641", + "MATRIX.tm642", + "MATRIX.tm643", + "MATRIX.tm644", + "MATRIX.tm645", + "MATRIX.tm646", + "MATRIX.tm651", + "MATRIX.tm652", + "MATRIX.tm653", + "MATRIX.tm654", + "MATRIX.tm655", + "MATRIX.tm656", + "MATRIX.tm661", + "MATRIX.tm662", + "MATRIX.tm663", + "MATRIX.tm664", + "MATRIX.tm665" + ] + } } - } - ], - "title": "ptc_trackline" - }, - "_NAME": "command_ptc_trackline" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_ptc_twiss.icase", - "command_ptc_twiss.deltap", - "command_ptc_twiss.closed_orbit", - "command_ptc_twiss.deltap_dependency", - "command_ptc_twiss.slice_magnets", - "command_ptc_twiss.range", - "command_ptc_twiss.file", - "command_ptc_twiss.initial_matrix_manual", - "command_ptc_twiss.initial_map_manual", - "command_ptc_twiss.beta0", - "command_ptc_twiss.ignore_map_orbit", - "command_ptc_twiss.ring_parameters", - "command_ptc_twiss.normal", - "command_ptc_twiss.trackrdts", - "command_ptc_twiss.betx", - "command_ptc_twiss.alfx", - "command_ptc_twiss.mux", - "command_ptc_twiss.bety", - "command_ptc_twiss.alfy", - "command_ptc_twiss.muy", - "command_ptc_twiss.betz", - "command_ptc_twiss.alfz", - "command_ptc_twiss.dx", - "command_ptc_twiss.dpx", - "command_ptc_twiss.dy", - "command_ptc_twiss.dpy", - "command_ptc_twiss.x", - "command_ptc_twiss.px", - "command_ptc_twiss.y", - "command_ptc_twiss.py", - "command_ptc_twiss.t", - "command_ptc_twiss.pt", - "command_ptc_twiss.re11", - "command_ptc_twiss.re12", - "command_ptc_twiss.re13", - "command_ptc_twiss.re14", - "command_ptc_twiss.re15", - "command_ptc_twiss.re16", - "command_ptc_twiss.re21", - "command_ptc_twiss.re22", - "command_ptc_twiss.re23", - "command_ptc_twiss.re24", - "command_ptc_twiss.re25", - "command_ptc_twiss.re26", - "command_ptc_twiss.re31", - "command_ptc_twiss.re32", - "command_ptc_twiss.re33", - "command_ptc_twiss.re34", - "command_ptc_twiss.re35", - "command_ptc_twiss.re36", - "command_ptc_twiss.re41", - "command_ptc_twiss.re42", - "command_ptc_twiss.re43", - "command_ptc_twiss.re44", - "command_ptc_twiss.re45", - "command_ptc_twiss.re46", - "command_ptc_twiss.re51", - "command_ptc_twiss.re52", - "command_ptc_twiss.re53", - "command_ptc_twiss.re54", - "command_ptc_twiss.re55", - "command_ptc_twiss.re56", - "command_ptc_twiss.re61", - "command_ptc_twiss.re62", - "command_ptc_twiss.re63", - "command_ptc_twiss.re64", - "command_ptc_twiss.re65", - "command_ptc_twiss.re66" - ] + ], + "title": "MATRIX" + }, + "_NAME": "MATRIX" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MONITOR.name", + "MONITOR.l", + "MONITOR.apertype", + "MONITOR.aperture", + "MONITOR.aper_offset", + "MONITOR.aper_tol" + ] + } } - } - ], - "title": "ptc_twiss" - }, - "_NAME": "command_ptc_twiss" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_resbeam.sequence" - ] + ], + "title": "MONITOR" + }, + "_NAME": "MONITOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MULTIPOLE.name", + "MULTIPOLE.lrad", + "MULTIPOLE.tilt", + "MULTIPOLE.knl", + "MULTIPOLE.ksl", + "MULTIPOLE.apertype", + "MULTIPOLE.aperture", + "MULTIPOLE.aper_offset", + "MULTIPOLE.aper_tol" + ] + } } - } - ], - "title": "resbeam" - }, - "_NAME": "command_resbeam" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_savebeta.label", - "command_savebeta.place", - "command_savebeta.sequence" - ] + ], + "title": "MULTIPOLE" + }, + "_NAME": "MULTIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "NLLENS.name", + "NLLENS.knll", + "NLLENS.cnll", + "NLLENS.apertype", + "NLLENS.aperture", + "NLLENS.aper_offset", + "NLLENS.aper_tol" + ] + } } - } - ], - "title": "savebeta" - }, - "_NAME": "command_savebeta" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_select.class", - "command_select.clear", - "command_select.column", - "command_select.flag", - "command_select.full", - "command_select.pattern", - "command_select.range", - "command_select.sequence", - "command_select.slice", - "command_select.thick" - ] + ], + "title": "NLLENS" + }, + "_NAME": "NLLENS" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "OCTUPOLE.name", + "OCTUPOLE.l", + "OCTUPOLE.k3", + "OCTUPOLE.k3s", + "OCTUPOLE.tilt", + "OCTUPOLE.apertype", + "OCTUPOLE.aperture", + "OCTUPOLE.aper_offset", + "OCTUPOLE.aper_tol" + ] + } } - } - ], - "title": "select" - }, - "_NAME": "command_select" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_set.format", - "command_set.sequence" - ] + ], + "title": "OCTUPOLE" + }, + "_NAME": "OCTUPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "PLACEHOLDER.name", + "PLACEHOLDER.l", + "PLACEHOLDER.apertype", + "PLACEHOLDER.aperture", + "PLACEHOLDER.aper_offset", + "PLACEHOLDER.aper_tol" + ] + } } - } - ], - "title": "set" - }, - "_NAME": "command_set" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_show.command" - ] + ], + "title": "PLACEHOLDER" + }, + "_NAME": "PLACEHOLDER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "QUADRUPOLE.name", + "QUADRUPOLE.l", + "QUADRUPOLE.k1", + "QUADRUPOLE.k1s", + "QUADRUPOLE.tilt", + "QUADRUPOLE.thick", + "QUADRUPOLE.apertype", + "QUADRUPOLE.aperture", + "QUADRUPOLE.aper_offset", + "QUADRUPOLE.aper_tol" + ] + } } - } - ], - "title": "show" - }, - "_NAME": "command_show" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_sodd.detune", - "command_sodd.distort1", - "command_sodd.distort2", - "command_sodd.multipole_order_range", - "command_sodd.noprint ", - "command_sodd.nosixtrack", - "command_sodd.print_all", - "command_sodd.print_at_end", - "command_sodd.start_stop" - ] + ], + "title": "QUADRUPOLE" + }, + "_NAME": "QUADRUPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RBEND.name", + "RBEND.l", + "RBEND.angle", + "RBEND.tilt", + "RBEND.k1", + "RBEND.k2", + "RBEND.e1", + "RBEND.e2", + "RBEND.fint", + "RBEND.fintx", + "RBEND.hgap", + "RBEND.h1", + "RBEND.h2", + "RBEND.add_angle", + "RBEND.thick", + "RBEND.apertype", + "RBEND.aperture", + "RBEND.aper_offset", + "RBEND.aper_tol" + ] + } } - } - ], - "title": "sodd" - }, - "_NAME": "command_sodd" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_touschek.tolerance", - "command_touschek.file" - ] + ], + "title": "RBEND" + }, + "_NAME": "RBEND" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RCOLLIMATOR.name", + "RCOLLIMATOR.l", + "RCOLLIMATOR.xsize", + "RCOLLIMATOR.ysize", + "RCOLLIMATOR.apertype", + "RCOLLIMATOR.aperture", + "RCOLLIMATOR.aper_offset", + "RCOLLIMATOR.aper_tol" + ] + } } - } - ], - "title": "touschek" - }, - "_NAME": "command_touschek" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_twiss.line", - "command_twiss.range", - "command_twiss.deltap", - "command_twiss.chrom", - "command_twiss.centre", - "command_twiss.tolerance", - "command_twiss.file", - "command_twiss.rmatrix", - "command_twiss.sectormap", - "command_twiss.sectortable", - "command_twiss.sectorfile", - "command_twiss.sectorpure", - "command_twiss.keeporbit", - "command_twiss.useorbit", - "command_twiss.ripken", - "command_twiss.betx", - "command_twiss.alfx", - "command_twiss.mux", - "command_twiss.dx", - "command_twiss.dpx", - "command_twiss.bety", - "command_twiss.muy", - "command_twiss.alfy", - "command_twiss.dy", - "command_twiss.dpy", - "command_twiss.x", - "command_twiss.px", - "command_twiss.y", - "command_twiss.py", - "command_twiss.t", - "command_twiss.pt", - "command_twiss.wx", - "command_twiss.phix", - "command_twiss.dmux", - "command_twiss.ddx", - "command_twiss.ddpx", - "command_twiss.wy", - "command_twiss.phiy", - "command_twiss.dmuy", - "command_twiss.ddy", - "command_twiss.ddpy", - "command_twiss.r11", - "command_twiss.r12", - "command_twiss.r21", - "command_twiss.r22" - ] + ], + "title": "RCOLLIMATOR" + }, + "_NAME": "RCOLLIMATOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFCAVITY.name", + "RFCAVITY.l", + "RFCAVITY.volt", + "RFCAVITY.lag", + "RFCAVITY.harmon", + "RFCAVITY.freq", + "RFCAVITY.apertype", + "RFCAVITY.aperture", + "RFCAVITY.aper_offset", + "RFCAVITY.aper_tol" + ] + } } - } - ], - "title": "twiss" - }, - "_NAME": "command_twiss" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_use.sequence", - "command_use.period" - ] + ], + "title": "RFCAVITY" + }, + "_NAME": "RFCAVITY" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFMULTIPOLE.name", + "RFMULTIPOLE.volt", + "RFMULTIPOLE.lag", + "RFMULTIPOLE.harmon", + "RFMULTIPOLE.freq", + "RFMULTIPOLE.lrad", + "RFMULTIPOLE.tilt", + "RFMULTIPOLE.knl", + "RFMULTIPOLE.ksl", + "RFMULTIPOLE.pnl", + "RFMULTIPOLE.psl", + "RFMULTIPOLE.apertype", + "RFMULTIPOLE.aperture", + "RFMULTIPOLE.aper_offset", + "RFMULTIPOLE.aper_tol" + ] + } } - } - ], - "title": "use" - }, - "_NAME": "command_use" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_vary.name", - "command_vary.step", - "command_vary.lower", - "command_vary.upper", - "command_vary.slope", - "command_vary.opt" - ] + ], + "title": "RFMULTIPOLE" + }, + "_NAME": "RFMULTIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SBEND.name", + "SBEND.l", + "SBEND.angle", + "SBEND.k1", + "SBEND.k2", + "SBEND.e1", + "SBEND.e2", + "SBEND.tilt", + "SBEND.h1", + "SBEND.h2", + "SBEND.hgap", + "SBEND.fint", + "SBEND.fintx", + "SBEND.thick", + "SBEND.apertype", + "SBEND.aperture", + "SBEND.aper_offset", + "SBEND.aper_tol" + ] + } } - } - ], - "title": "vary" - }, - "_NAME": "command_vary" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "twissEllipseReport.dim" - ] + ], + "title": "SBEND" + }, + "_NAME": "SBEND" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SEXTUPOLE.name", + "SEXTUPOLE.l", + "SEXTUPOLE.k2", + "SEXTUPOLE.k2s", + "SEXTUPOLE.tilt", + "SEXTUPOLE.apertype", + "SEXTUPOLE.aperture", + "SEXTUPOLE.aper_offset", + "SEXTUPOLE.aper_tol" + ] + } } - } - ], - "title": "Twiss Ellipse" - }, - "_NAME": "twissEllipseReport" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.x" - ] - } - } - ] - } - }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.y1", - "elementAnimation.y2", - "elementAnimation.y3" - ] - } - } - ] - } - } - ] + ], + "title": "SEXTUPOLE" + }, + "_NAME": "SEXTUPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SOLENOID.name", + "SOLENOID.l", + "SOLENOID.ks", + "SOLENOID.ksi", + "SOLENOID.apertype", + "SOLENOID.aperture", + "SOLENOID.aper_offset", + "SOLENOID.aper_tol" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.includeLattice" - ] + ], + "title": "SOLENOID" + }, + "_NAME": "SOLENOID" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SROTATION.name", + "SROTATION.angle", + "SROTATION.apertype", + "SROTATION.aperture", + "SROTATION.aper_offset", + "SROTATION.aper_tol" + ] + } } - } - ], - "title": "Twiss Parameters" - }, - "_NAME": "twissAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "twissReport.y1", - "twissReport.y2", - "twissReport.y3", - "twissReport.includeLattice" - ] + ], + "title": "SROTATION" + }, + "_NAME": "SROTATION" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TRANSLATION.name", + "TRANSLATION.dx", + "TRANSLATION.dy", + "TRANSLATION.ds" + ] + } } - } - ], - "title": "Twiss Parameters" - }, - "_NAME": "twissReport" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "BEAMBEAM.name", - "BEAMBEAM.sigx", - "BEAMBEAM.sigy", - "BEAMBEAM.xma", - "BEAMBEAM.yma", - "BEAMBEAM.charge", - "BEAMBEAM.bbshape", - "BEAMBEAM.width", - "BEAMBEAM.bbdir", - "BEAMBEAM.apertype", - "BEAMBEAM.aperture", - "BEAMBEAM.aper_offset", - "BEAMBEAM.aper_tol" - ] + ], + "title": "TRANSLATION" + }, + "_NAME": "TRANSLATION" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TWCAVITY.name", + "TWCAVITY.l", + "TWCAVITY.volt", + "TWCAVITY.freq", + "TWCAVITY.lag", + "TWCAVITY.psi", + "TWCAVITY.delta_lag", + "TWCAVITY.apertype", + "TWCAVITY.aperture", + "TWCAVITY.aper_offset", + "TWCAVITY.aper_tol" + ] + } } - } - ], - "title": "BEAMBEAM" - }, - "_NAME": "BEAMBEAM" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "CHANGEREF.name", - "CHANGEREF.patch_ang", - "CHANGEREF.patch_trans", - "CHANGEREF.apertype", - "CHANGEREF.aperture", - "CHANGEREF.aper_offset", - "CHANGEREF.aper_tol" - ] + ], + "title": "TWCAVITY" + }, + "_NAME": "TWCAVITY" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VACDIPOLE.name", + "VACDIPOLE.l", + "VACDIPOLE.volt", + "VACDIPOLE.freq", + "VACDIPOLE.lag", + "VACDIPOLE.ramp1", + "VACDIPOLE.ramp2", + "VACDIPOLE.ramp3", + "VACDIPOLE.ramp4", + "VACDIPOLE.apertype", + "VACDIPOLE.aperture", + "VACDIPOLE.aper_offset", + "VACDIPOLE.aper_tol" + ] + } } - } - ], - "title": "CHANGEREF" - }, - "_NAME": "CHANGEREF" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "COLLIMATOR.name", - "COLLIMATOR.l", - "COLLIMATOR.apertype", - "COLLIMATOR.aperture", - "COLLIMATOR.aper_offset", - "COLLIMATOR.aper_tol" - ] + ], + "title": "VACDIPOLE" + }, + "_NAME": "VACDIPOLE" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VKICKER.name", + "VKICKER.l", + "VKICKER.kick", + "VKICKER.tilt", + "VKICKER.apertype", + "VKICKER.aperture", + "VKICKER.aper_offset", + "VKICKER.aper_tol" + ] + } } - } - ], - "title": "COLLIMATOR" - }, - "_NAME": "COLLIMATOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "CRABCAVITY.name", - "CRABCAVITY.l", - "CRABCAVITY.volt", - "CRABCAVITY.lag", - "CRABCAVITY.freq", - "CRABCAVITY.rv1", - "CRABCAVITY.rv2", - "CRABCAVITY.rv3", - "CRABCAVITY.rv4", - "CRABCAVITY.rph1", - "CRABCAVITY.rph2", - "CRABCAVITY.lagf", - "CRABCAVITY.apertype", - "CRABCAVITY.aperture", - "CRABCAVITY.aper_offset", - "CRABCAVITY.aper_tol" - ] + ], + "title": "VKICKER" + }, + "_NAME": "VKICKER" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VMONITOR.name", + "VMONITOR.l", + "VMONITOR.apertype", + "VMONITOR.aperture", + "VMONITOR.aper_offset", + "VMONITOR.aper_tol" + ] + } } - } - ], - "title": "CRABCAVITY" - }, - "_NAME": "CRABCAVITY" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "DIPEDGE.name", - "DIPEDGE.h", - "DIPEDGE.e1", - "DIPEDGE.fint", - "DIPEDGE.hgap", - "DIPEDGE.tilt", - "DIPEDGE.apertype", - "DIPEDGE.aperture", - "DIPEDGE.aper_offset", - "DIPEDGE.aper_tol" - ] + ], + "title": "VMONITOR" + }, + "_NAME": "VMONITOR" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "XROTATION.name", + "XROTATION.angle", + "XROTATION.apertype", + "XROTATION.aperture", + "XROTATION.aper_offset", + "XROTATION.aper_tol" + ] + } } - } - ], - "title": "DIPEDGE" - }, - "_NAME": "DIPEDGE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "DRIFT.name", - "DRIFT.l" - ] + ], + "title": "XROTATION" + }, + "_NAME": "XROTATION" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "YROTATION.name", + "YROTATION.angle", + "YROTATION.apertype", + "YROTATION.aperture", + "YROTATION.aper_offset", + "YROTATION.aper_tol" + ] + } } - } - ], - "title": "DRIFT" - }, - "_NAME": "DRIFT" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "ECOLLIMATOR.name", - "ECOLLIMATOR.l", - "ECOLLIMATOR.xsize", - "ECOLLIMATOR.ysize", - "ECOLLIMATOR.apertype", - "ECOLLIMATOR.aperture", - "ECOLLIMATOR.aper_offset", - "ECOLLIMATOR.aper_tol" - ] + ], + "title": "YROTATION" + }, + "_NAME": "YROTATION" + } + ], + [ + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.particle", + "command_beam.mass", + "command_beam.charge", + "command_beam.energy", + "command_beam.pc", + "command_beam.gamma", + "command_beam.beta", + "command_beam.brho", + "command_beam.ex", + "command_beam.exn", + "command_beam.ey", + "command_beam.eyn", + "command_beam.et", + "command_beam.sequence", + "command_beam.sigt", + "command_beam.sige", + "command_beam.kbunch", + "command_beam.npart", + "command_beam.bcurrent", + "command_beam.bunched", + "command_beam.radiate", + "command_beam.bv" + ] + } } - } - ], - "title": "ECOLLIMATOR" - }, - "_NAME": "ECOLLIMATOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HACDIPOLE.name", - "HACDIPOLE.l", - "HACDIPOLE.volt", - "HACDIPOLE.freq", - "HACDIPOLE.lag", - "HACDIPOLE.ramp1", - "HACDIPOLE.ramp2", - "HACDIPOLE.ramp3", - "HACDIPOLE.ramp4", - "HACDIPOLE.apertype", - "HACDIPOLE.aperture", - "HACDIPOLE.aper_offset", - "HACDIPOLE.aper_tol" - ] + ], + "title": "beam" + }, + "_NAME": "command_beam" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beta0.betx", + "command_beta0.alfx", + "command_beta0.bety", + "command_beta0.mux", + "command_beta0.alfy", + "command_beta0.muy", + "command_beta0.x", + "command_beta0.px", + "command_beta0.y", + "command_beta0.py", + "command_beta0.t", + "command_beta0.pt", + "command_beta0.dx", + "command_beta0.dpx", + "command_beta0.dy", + "command_beta0.dpy", + "command_beta0.wx", + "command_beta0.phix", + "command_beta0.dmux", + "command_beta0.wy", + "command_beta0.phiy", + "command_beta0.dmuy", + "command_beta0.ddx", + "command_beta0.ddpx", + "command_beta0.ddy", + "command_beta0.ddpy", + "command_beta0.r11", + "command_beta0.r12", + "command_beta0.r21", + "command_beta0.r22", + "command_beta0.energy" + ] + } } - } - ], - "title": "HACDIPOLE" - }, - "_NAME": "HACDIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HKICKER.name", - "HKICKER.l", - "HKICKER.kick", - "HKICKER.tilt", - "HKICKER.apertype", - "HKICKER.aperture", - "HKICKER.aper_offset", - "HKICKER.aper_tol" - ] + ], + "title": "beta0" + }, + "_NAME": "command_beta0" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_constraint.sequence", + "command_constraint.range", + "command_constraint.alfx", + "command_constraint.alfy", + "command_constraint.betx", + "command_constraint.bety", + "command_constraint.dpx", + "command_constraint.dpy", + "command_constraint.dx", + "command_constraint.dy", + "command_constraint.mux", + "command_constraint.muy", + "command_constraint.px", + "command_constraint.py", + "command_constraint.x", + "command_constraint.y" + ] + } } - } - ], - "title": "HKICKER" - }, - "_NAME": "HKICKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HMONITOR.name", - "HMONITOR.l", - "HMONITOR.apertype", - "HMONITOR.aperture", - "HMONITOR.aper_offset", - "HMONITOR.aper_tol" - ] + ], + "title": "constraint" + }, + "_NAME": "command_constraint" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ealign.dx", + "command_ealign.dy", + "command_ealign.ds", + "command_ealign.dphi", + "command_ealign.dtheta", + "command_ealign.dpsi", + "command_ealign.mrex", + "command_ealign.mrey", + "command_ealign.mscalx", + "command_ealign.mscaly", + "command_ealign.arex", + "command_ealign.arey" + ] + } } - } - ], - "title": "HMONITOR" - }, - "_NAME": "HMONITOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "INSTRUMENT.name", - "INSTRUMENT.l", - "INSTRUMENT.apertype", - "INSTRUMENT.aperture", - "INSTRUMENT.aper_offset", - "INSTRUMENT.aper_tol" - ] + ], + "title": "ealign" + }, + "_NAME": "command_ealign" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_emit.deltap", + "command_emit.tol" + ] + } } - } - ], - "title": "INSTRUMENT" - }, - "_NAME": "INSTRUMENT" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "KICKER.name", - "KICKER.l", - "KICKER.hkick", - "KICKER.vkick", - "KICKER.tilt", - "KICKER.apertype", - "KICKER.aperture", - "KICKER.aper_offset", - "KICKER.aper_tol" - ] + ], + "title": "emit" + }, + "_NAME": "command_emit" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "endmatch" + }, + "_NAME": "command_endmatch" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_global.sequence", + "command_global.q1", + "command_global.q2", + "command_global.dq1", + "command_global.dq2" + ] + } } - } - ], - "title": "KICKER" - }, - "_NAME": "KICKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MARKER.name", - "MARKER.apertype", - "MARKER.aperture", - "MARKER.aper_offset", - "MARKER.aper_tol" - ] + ], + "title": "global" + }, + "_NAME": "command_global" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_jacobian.calls", + "command_jacobian.tolerance", + "command_jacobian.repeat", + "command_jacobian.strategy", + "command_jacobian.cool", + "command_jacobian.balance", + "command_jacobian.random" + ] + } } - } - ], - "title": "MARKER" - }, - "_NAME": "MARKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MATRIX.name", - "MATRIX.l", - "MATRIX.kick1", - "MATRIX.kick6", - "MATRIX.rm11", - "MATRIX.rm66", - "MATRIX.tm111", - "MATRIX.tm666", - "MATRIX.kick2", - "MATRIX.kick3", - "MATRIX.kick4", - "MATRIX.kick5", - "MATRIX.rm12", - "MATRIX.rm13", - "MATRIX.rm14", - "MATRIX.rm15", - "MATRIX.rm16", - "MATRIX.rm21", - "MATRIX.rm22", - "MATRIX.rm23", - "MATRIX.rm24", - "MATRIX.rm25", - "MATRIX.rm26", - "MATRIX.rm31", - "MATRIX.rm32", - "MATRIX.rm33", - "MATRIX.rm34", - "MATRIX.rm35", - "MATRIX.rm36", - "MATRIX.rm41", - "MATRIX.rm42", - "MATRIX.rm43", - "MATRIX.rm44", - "MATRIX.rm45", - "MATRIX.rm46", - "MATRIX.rm51", - "MATRIX.rm52", - "MATRIX.rm53", - "MATRIX.rm54", - "MATRIX.rm55", - "MATRIX.rm56", - "MATRIX.rm61", - "MATRIX.rm62", - "MATRIX.rm63", - "MATRIX.rm64", - "MATRIX.rm65", - "MATRIX.tm112", - "MATRIX.tm113", - "MATRIX.tm114", - "MATRIX.tm115", - "MATRIX.tm116", - "MATRIX.tm121", - "MATRIX.tm122", - "MATRIX.tm123", - "MATRIX.tm124", - "MATRIX.tm125", - "MATRIX.tm126", - "MATRIX.tm131", - "MATRIX.tm132", - "MATRIX.tm133", - "MATRIX.tm134", - "MATRIX.tm135", - "MATRIX.tm136", - "MATRIX.tm141", - "MATRIX.tm142", - "MATRIX.tm143", - "MATRIX.tm144", - "MATRIX.tm145", - "MATRIX.tm146", - "MATRIX.tm151", - "MATRIX.tm152", - "MATRIX.tm153", - "MATRIX.tm154", - "MATRIX.tm155", - "MATRIX.tm156", - "MATRIX.tm161", - "MATRIX.tm162", - "MATRIX.tm163", - "MATRIX.tm164", - "MATRIX.tm165", - "MATRIX.tm166", - "MATRIX.tm211", - "MATRIX.tm212", - "MATRIX.tm213", - "MATRIX.tm214", - "MATRIX.tm215", - "MATRIX.tm216", - "MATRIX.tm221", - "MATRIX.tm222", - "MATRIX.tm223", - "MATRIX.tm224", - "MATRIX.tm225", - "MATRIX.tm226", - "MATRIX.tm231", - "MATRIX.tm232", - "MATRIX.tm233", - "MATRIX.tm234", - "MATRIX.tm235", - "MATRIX.tm236", - "MATRIX.tm241", - "MATRIX.tm242", - "MATRIX.tm243", - "MATRIX.tm244", - "MATRIX.tm245", - "MATRIX.tm246", - "MATRIX.tm251", - "MATRIX.tm252", - "MATRIX.tm253", - "MATRIX.tm254", - "MATRIX.tm255", - "MATRIX.tm256", - "MATRIX.tm261", - "MATRIX.tm262", - "MATRIX.tm263", - "MATRIX.tm264", - "MATRIX.tm265", - "MATRIX.tm266", - "MATRIX.tm311", - "MATRIX.tm312", - "MATRIX.tm313", - "MATRIX.tm314", - "MATRIX.tm315", - "MATRIX.tm316", - "MATRIX.tm321", - "MATRIX.tm322", - "MATRIX.tm323", - "MATRIX.tm324", - "MATRIX.tm325", - "MATRIX.tm326", - "MATRIX.tm331", - "MATRIX.tm332", - "MATRIX.tm333", - "MATRIX.tm334", - "MATRIX.tm335", - "MATRIX.tm336", - "MATRIX.tm341", - "MATRIX.tm342", - "MATRIX.tm343", - "MATRIX.tm344", - "MATRIX.tm345", - "MATRIX.tm346", - "MATRIX.tm351", - "MATRIX.tm352", - "MATRIX.tm353", - "MATRIX.tm354", - "MATRIX.tm355", - "MATRIX.tm356", - "MATRIX.tm361", - "MATRIX.tm362", - "MATRIX.tm363", - "MATRIX.tm364", - "MATRIX.tm365", - "MATRIX.tm366", - "MATRIX.tm411", - "MATRIX.tm412", - "MATRIX.tm413", - "MATRIX.tm414", - "MATRIX.tm415", - "MATRIX.tm416", - "MATRIX.tm421", - "MATRIX.tm422", - "MATRIX.tm423", - "MATRIX.tm424", - "MATRIX.tm425", - "MATRIX.tm426", - "MATRIX.tm431", - "MATRIX.tm432", - "MATRIX.tm433", - "MATRIX.tm434", - "MATRIX.tm435", - "MATRIX.tm436", - "MATRIX.tm441", - "MATRIX.tm442", - "MATRIX.tm443", - "MATRIX.tm444", - "MATRIX.tm445", - "MATRIX.tm446", - "MATRIX.tm451", - "MATRIX.tm452", - "MATRIX.tm453", - "MATRIX.tm454", - "MATRIX.tm455", - "MATRIX.tm456", - "MATRIX.tm461", - "MATRIX.tm462", - "MATRIX.tm463", - "MATRIX.tm464", - "MATRIX.tm465", - "MATRIX.tm466", - "MATRIX.tm511", - "MATRIX.tm512", - "MATRIX.tm513", - "MATRIX.tm514", - "MATRIX.tm515", - "MATRIX.tm516", - "MATRIX.tm521", - "MATRIX.tm522", - "MATRIX.tm523", - "MATRIX.tm524", - "MATRIX.tm525", - "MATRIX.tm526", - "MATRIX.tm531", - "MATRIX.tm532", - "MATRIX.tm533", - "MATRIX.tm534", - "MATRIX.tm535", - "MATRIX.tm536", - "MATRIX.tm541", - "MATRIX.tm542", - "MATRIX.tm543", - "MATRIX.tm544", - "MATRIX.tm545", - "MATRIX.tm546", - "MATRIX.tm551", - "MATRIX.tm552", - "MATRIX.tm553", - "MATRIX.tm554", - "MATRIX.tm555", - "MATRIX.tm556", - "MATRIX.tm561", - "MATRIX.tm562", - "MATRIX.tm563", - "MATRIX.tm564", - "MATRIX.tm565", - "MATRIX.tm566", - "MATRIX.tm611", - "MATRIX.tm612", - "MATRIX.tm613", - "MATRIX.tm614", - "MATRIX.tm615", - "MATRIX.tm616", - "MATRIX.tm621", - "MATRIX.tm622", - "MATRIX.tm623", - "MATRIX.tm624", - "MATRIX.tm625", - "MATRIX.tm626", - "MATRIX.tm631", - "MATRIX.tm632", - "MATRIX.tm633", - "MATRIX.tm634", - "MATRIX.tm635", - "MATRIX.tm636", - "MATRIX.tm641", - "MATRIX.tm642", - "MATRIX.tm643", - "MATRIX.tm644", - "MATRIX.tm645", - "MATRIX.tm646", - "MATRIX.tm651", - "MATRIX.tm652", - "MATRIX.tm653", - "MATRIX.tm654", - "MATRIX.tm655", - "MATRIX.tm656", - "MATRIX.tm661", - "MATRIX.tm662", - "MATRIX.tm663", - "MATRIX.tm664", - "MATRIX.tm665" - ] + ], + "title": "jacobian" + }, + "_NAME": "command_jacobian" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_lmdif.calls", + "command_lmdif.tolerance" + ] + } } - } - ], - "title": "MATRIX" - }, - "_NAME": "MATRIX" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MONITOR.name", - "MONITOR.l", - "MONITOR.apertype", - "MONITOR.aperture", - "MONITOR.aper_offset", - "MONITOR.aper_tol" - ] + ], + "title": "lmdif" + }, + "_NAME": "command_lmdif" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_makethin.sequence", + "command_makethin.style", + "command_makethin.makedipedge" + ] + } } - } - ], - "title": "MONITOR" - }, - "_NAME": "MONITOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MULTIPOLE.name", - "MULTIPOLE.lrad", - "MULTIPOLE.tilt", - "MULTIPOLE.knl", - "MULTIPOLE.ksl", - "MULTIPOLE.apertype", - "MULTIPOLE.aperture", - "MULTIPOLE.aper_offset", - "MULTIPOLE.aper_tol" - ] + ], + "title": "makethin" + }, + "_NAME": "command_makethin" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_match.sequence", + "command_match.alfx", + "command_match.alfy", + "command_match.betx", + "command_match.bety", + "command_match.deltap", + "command_match.dpx", + "command_match.dpy", + "command_match.dx", + "command_match.dy", + "command_match.mux", + "command_match.muy", + "command_match.px", + "command_match.py", + "command_match.x", + "command_match.y" + ] + } } - } - ], - "title": "MULTIPOLE" - }, - "_NAME": "MULTIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "NLLENS.name", - "NLLENS.knll", - "NLLENS.cnll", - "NLLENS.apertype", - "NLLENS.aperture", - "NLLENS.aper_offset", - "NLLENS.aper_tol" - ] + ], + "title": "match" + }, + "_NAME": "command_match" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_migrad.calls", + "command_migrad.tolerance", + "command_migrad.strategy" + ] + } } - } - ], - "title": "NLLENS" - }, - "_NAME": "NLLENS" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "OCTUPOLE.name", - "OCTUPOLE.l", - "OCTUPOLE.k3", - "OCTUPOLE.k3s", - "OCTUPOLE.tilt", - "OCTUPOLE.apertype", - "OCTUPOLE.aperture", - "OCTUPOLE.aper_offset", - "OCTUPOLE.aper_tol" - ] + ], + "title": "migrad" + }, + "_NAME": "command_migrad" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_option.bborbit", + "command_option.debug", + "command_option.echo", + "command_option.echomacro", + "command_option.info", + "command_option.no_fatal_stop", + "command_option.rbarc", + "command_option.reset", + "command_option.sympl", + "command_option.tell", + "command_option.thin_foc", + "command_option.threader", + "command_option.trace", + "command_option.twiss_print", + "command_option.verbose", + "command_option.verify", + "command_option.warn" + ] + } } - } - ], - "title": "OCTUPOLE" - }, - "_NAME": "OCTUPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "PLACEHOLDER.name", - "PLACEHOLDER.l", - "PLACEHOLDER.apertype", - "PLACEHOLDER.aperture", - "PLACEHOLDER.aper_offset", - "PLACEHOLDER.aper_tol" - ] + ], + "title": "option" + }, + "_NAME": "command_option" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_create_layout.time", + "command_ptc_create_layout.model", + "command_ptc_create_layout.method", + "command_ptc_create_layout.nst", + "command_ptc_create_layout.exact", + "command_ptc_create_layout.offset_deltap", + "command_ptc_create_layout.errors_out", + "command_ptc_create_layout.magnet_name", + "command_ptc_create_layout.resplit", + "command_ptc_create_layout.thin", + "command_ptc_create_layout.xbend", + "command_ptc_create_layout.even" + ] + } } - } - ], - "title": "PLACEHOLDER" - }, - "_NAME": "PLACEHOLDER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "QUADRUPOLE.name", - "QUADRUPOLE.l", - "QUADRUPOLE.k1", - "QUADRUPOLE.k1s", - "QUADRUPOLE.tilt", - "QUADRUPOLE.thick", - "QUADRUPOLE.apertype", - "QUADRUPOLE.aperture", - "QUADRUPOLE.aper_offset", - "QUADRUPOLE.aper_tol" - ] + ], + "title": "ptc_create_layout" + }, + "_NAME": "command_ptc_create_layout" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_create_universe.sector_nmul_max", + "command_ptc_create_universe.sector_nmul", + "command_ptc_create_universe.ntpsa", + "command_ptc_create_universe.symprint" + ] + } } - } - ], - "title": "QUADRUPOLE" - }, - "_NAME": "QUADRUPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RBEND.name", - "RBEND.l", - "RBEND.angle", - "RBEND.tilt", - "RBEND.k1", - "RBEND.k2", - "RBEND.e1", - "RBEND.e2", - "RBEND.fint", - "RBEND.fintx", - "RBEND.hgap", - "RBEND.h1", - "RBEND.h2", - "RBEND.add_angle", - "RBEND.thick", - "RBEND.apertype", - "RBEND.aperture", - "RBEND.aper_offset", - "RBEND.aper_tol" - ] + ], + "title": "ptc_create_universe" + }, + "_NAME": "command_ptc_create_universe" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "ptc_create_end" + }, + "_NAME": "command_ptc_end" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_normal.closed_orbit", + "command_ptc_normal.deltap", + "command_ptc_normal.icase", + "command_ptc_normal.map_table", + "command_ptc_normal.no", + "command_ptc_normal.normal" + ] + } } - } - ], - "title": "RBEND" - }, - "_NAME": "RBEND" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RCOLLIMATOR.name", - "RCOLLIMATOR.l", - "RCOLLIMATOR.xsize", - "RCOLLIMATOR.ysize", - "RCOLLIMATOR.apertype", - "RCOLLIMATOR.aperture", - "RCOLLIMATOR.aper_offset", - "RCOLLIMATOR.aper_tol" - ] + ], + "title": "ptc_normal" + }, + "_NAME": "command_ptc_normal" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_observe.place" + ] + } } - } - ], - "title": "RCOLLIMATOR" - }, - "_NAME": "RCOLLIMATOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RFCAVITY.name", - "RFCAVITY.l", - "RFCAVITY.volt", - "RFCAVITY.lag", - "RFCAVITY.harmon", - "RFCAVITY.freq", - "RFCAVITY.apertype", - "RFCAVITY.aperture", - "RFCAVITY.aper_offset", - "RFCAVITY.aper_tol" - ] + ], + "title": "ptc_observe" + }, + "_NAME": "command_ptc_observe" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_select.table", + "command_ptc_select.column", + "command_ptc_select.polynomial", + "command_ptc_select.monomial", + "command_ptc_select.parametric", + "command_ptc_select.quantity" + ] + } } - } - ], - "title": "RFCAVITY" - }, - "_NAME": "RFCAVITY" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RFMULTIPOLE.name", - "RFMULTIPOLE.volt", - "RFMULTIPOLE.lag", - "RFMULTIPOLE.harmon", - "RFMULTIPOLE.freq", - "RFMULTIPOLE.lrad", - "RFMULTIPOLE.tilt", - "RFMULTIPOLE.knl", - "RFMULTIPOLE.ksl", - "RFMULTIPOLE.pnl", - "RFMULTIPOLE.psl", - "RFMULTIPOLE.apertype", - "RFMULTIPOLE.aperture", - "RFMULTIPOLE.aper_offset", - "RFMULTIPOLE.aper_tol" - ] + ], + "title": "ptc_select" + }, + "_NAME": "command_ptc_select" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_setswitch.debuglevel", + "command_ptc_setswitch.exact_mis", + "command_ptc_setswitch.totalpath", + "command_ptc_setswitch.radiation", + "command_ptc_setswitch.envelope", + "command_ptc_setswitch.stochastic", + "command_ptc_setswitch.modulation", + "command_ptc_setswitch.fringe" + ] + } } - } - ], - "title": "RFMULTIPOLE" - }, - "_NAME": "RFMULTIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SBEND.name", - "SBEND.l", - "SBEND.angle", - "SBEND.k1", - "SBEND.k2", - "SBEND.e1", - "SBEND.e2", - "SBEND.tilt", - "SBEND.h1", - "SBEND.h2", - "SBEND.hgap", - "SBEND.fint", - "SBEND.fintx", - "SBEND.thick", - "SBEND.apertype", - "SBEND.aperture", - "SBEND.aper_offset", - "SBEND.aper_tol" - ] + ], + "title": "ptc_setswitch" + }, + "_NAME": "command_ptc_setswitch" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_start.x", + "command_ptc_start.px", + "command_ptc_start.y", + "command_ptc_start.py", + "command_ptc_start.t", + "command_ptc_start.pt", + "command_ptc_start.fx", + "command_ptc_start.phix", + "command_ptc_start.fy", + "command_ptc_start.phiy", + "command_ptc_start.ft", + "command_ptc_start.phit" + ] + } } - } - ], - "title": "SBEND" - }, - "_NAME": "SBEND" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SEXTUPOLE.name", - "SEXTUPOLE.l", - "SEXTUPOLE.k2", - "SEXTUPOLE.k2s", - "SEXTUPOLE.tilt", - "SEXTUPOLE.apertype", - "SEXTUPOLE.aperture", - "SEXTUPOLE.aper_offset", - "SEXTUPOLE.aper_tol" - ] + ], + "title": "ptc_start" + }, + "_NAME": "command_ptc_start" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_track.deltap", + "command_ptc_track.icase", + "command_ptc_track.closed_orbit", + "command_ptc_track.element_by_element", + "command_ptc_track.turns", + "command_ptc_track.maxaper", + "command_ptc_track.norm_no", + "command_ptc_track.file", + "command_ptc_track.norm_out", + "command_ptc_track.ffile", + "command_ptc_track.radiation", + "command_ptc_track.radiation_model1", + "command_ptc_track.radiation_energy_loss", + "command_ptc_track.radiation_quad", + "command_ptc_track.beam_envelope", + "command_ptc_track.space_charge" + ] + } } - } - ], - "title": "SEXTUPOLE" - }, - "_NAME": "SEXTUPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SOLENOID.name", - "SOLENOID.l", - "SOLENOID.ks", - "SOLENOID.ksi", - "SOLENOID.apertype", - "SOLENOID.aperture", - "SOLENOID.aper_offset", - "SOLENOID.aper_tol" - ] + ], + "title": "ptc_track" + }, + "_NAME": "command_ptc_track" + }, + { + "layout": "panel", + "config": { + "advanced": [], + "title": "ptc_track_end" + }, + "_NAME": "command_ptc_track_end" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_trackline.turns", + "command_ptc_trackline.file", + "command_ptc_trackline.everystep", + "command_ptc_trackline.gcs" + ] + } } - } - ], - "title": "SOLENOID" - }, - "_NAME": "SOLENOID" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SROTATION.name", - "SROTATION.angle", - "SROTATION.apertype", - "SROTATION.aperture", - "SROTATION.aper_offset", - "SROTATION.aper_tol" - ] + ], + "title": "ptc_trackline" + }, + "_NAME": "command_ptc_trackline" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_ptc_twiss.icase", + "command_ptc_twiss.deltap", + "command_ptc_twiss.closed_orbit", + "command_ptc_twiss.deltap_dependency", + "command_ptc_twiss.slice_magnets", + "command_ptc_twiss.range", + "command_ptc_twiss.file", + "command_ptc_twiss.initial_matrix_manual", + "command_ptc_twiss.initial_map_manual", + "command_ptc_twiss.beta0", + "command_ptc_twiss.ignore_map_orbit", + "command_ptc_twiss.ring_parameters", + "command_ptc_twiss.normal", + "command_ptc_twiss.trackrdts", + "command_ptc_twiss.betx", + "command_ptc_twiss.alfx", + "command_ptc_twiss.mux", + "command_ptc_twiss.bety", + "command_ptc_twiss.alfy", + "command_ptc_twiss.muy", + "command_ptc_twiss.betz", + "command_ptc_twiss.alfz", + "command_ptc_twiss.dx", + "command_ptc_twiss.dpx", + "command_ptc_twiss.dy", + "command_ptc_twiss.dpy", + "command_ptc_twiss.x", + "command_ptc_twiss.px", + "command_ptc_twiss.y", + "command_ptc_twiss.py", + "command_ptc_twiss.t", + "command_ptc_twiss.pt", + "command_ptc_twiss.re11", + "command_ptc_twiss.re12", + "command_ptc_twiss.re13", + "command_ptc_twiss.re14", + "command_ptc_twiss.re15", + "command_ptc_twiss.re16", + "command_ptc_twiss.re21", + "command_ptc_twiss.re22", + "command_ptc_twiss.re23", + "command_ptc_twiss.re24", + "command_ptc_twiss.re25", + "command_ptc_twiss.re26", + "command_ptc_twiss.re31", + "command_ptc_twiss.re32", + "command_ptc_twiss.re33", + "command_ptc_twiss.re34", + "command_ptc_twiss.re35", + "command_ptc_twiss.re36", + "command_ptc_twiss.re41", + "command_ptc_twiss.re42", + "command_ptc_twiss.re43", + "command_ptc_twiss.re44", + "command_ptc_twiss.re45", + "command_ptc_twiss.re46", + "command_ptc_twiss.re51", + "command_ptc_twiss.re52", + "command_ptc_twiss.re53", + "command_ptc_twiss.re54", + "command_ptc_twiss.re55", + "command_ptc_twiss.re56", + "command_ptc_twiss.re61", + "command_ptc_twiss.re62", + "command_ptc_twiss.re63", + "command_ptc_twiss.re64", + "command_ptc_twiss.re65", + "command_ptc_twiss.re66" + ] + } } - } - ], - "title": "SROTATION" - }, - "_NAME": "SROTATION" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "TRANSLATION.name", - "TRANSLATION.dx", - "TRANSLATION.dy", - "TRANSLATION.ds" - ] + ], + "title": "ptc_twiss" + }, + "_NAME": "command_ptc_twiss" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_resbeam.sequence" + ] + } } - } - ], - "title": "TRANSLATION" - }, - "_NAME": "TRANSLATION" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "TWCAVITY.name", - "TWCAVITY.l", - "TWCAVITY.volt", - "TWCAVITY.freq", - "TWCAVITY.lag", - "TWCAVITY.psi", - "TWCAVITY.delta_lag", - "TWCAVITY.apertype", - "TWCAVITY.aperture", - "TWCAVITY.aper_offset", - "TWCAVITY.aper_tol" - ] + ], + "title": "resbeam" + }, + "_NAME": "command_resbeam" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_savebeta.label", + "command_savebeta.place", + "command_savebeta.sequence" + ] + } } - } - ], - "title": "TWCAVITY" - }, - "_NAME": "TWCAVITY" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VACDIPOLE.name", - "VACDIPOLE.l", - "VACDIPOLE.volt", - "VACDIPOLE.freq", - "VACDIPOLE.lag", - "VACDIPOLE.ramp1", - "VACDIPOLE.ramp2", - "VACDIPOLE.ramp3", - "VACDIPOLE.ramp4", - "VACDIPOLE.apertype", - "VACDIPOLE.aperture", - "VACDIPOLE.aper_offset", - "VACDIPOLE.aper_tol" - ] + ], + "title": "savebeta" + }, + "_NAME": "command_savebeta" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_select.class", + "command_select.clear", + "command_select.column", + "command_select.flag", + "command_select.full", + "command_select.pattern", + "command_select.range", + "command_select.sequence", + "command_select.slice", + "command_select.thick" + ] + } } - } - ], - "title": "VACDIPOLE" - }, - "_NAME": "VACDIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VKICKER.name", - "VKICKER.l", - "VKICKER.kick", - "VKICKER.tilt", - "VKICKER.apertype", - "VKICKER.aperture", - "VKICKER.aper_offset", - "VKICKER.aper_tol" - ] + ], + "title": "select" + }, + "_NAME": "command_select" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_set.format", + "command_set.sequence" + ] + } } - } - ], - "title": "VKICKER" - }, - "_NAME": "VKICKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VMONITOR.name", - "VMONITOR.l", - "VMONITOR.apertype", - "VMONITOR.aperture", - "VMONITOR.aper_offset", - "VMONITOR.aper_tol" - ] + ], + "title": "set" + }, + "_NAME": "command_set" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_show.command" + ] + } } - } - ], - "title": "VMONITOR" - }, - "_NAME": "VMONITOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "XROTATION.name", - "XROTATION.angle", - "XROTATION.apertype", - "XROTATION.aperture", - "XROTATION.aper_offset", - "XROTATION.aper_tol" - ] + ], + "title": "show" + }, + "_NAME": "command_show" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_sodd.detune", + "command_sodd.distort1", + "command_sodd.distort2", + "command_sodd.multipole_order_range", + "command_sodd.noprint ", + "command_sodd.nosixtrack", + "command_sodd.print_all", + "command_sodd.print_at_end", + "command_sodd.start_stop" + ] + } } - } - ], - "title": "XROTATION" - }, - "_NAME": "XROTATION" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "YROTATION.name", - "YROTATION.angle", - "YROTATION.apertype", - "YROTATION.aperture", - "YROTATION.aper_offset", - "YROTATION.aper_tol" - ] + ], + "title": "sodd" + }, + "_NAME": "command_sodd" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_touschek.tolerance", + "command_touschek.file" + ] + } } - } - ], - "title": "YROTATION" - }, - "_NAME": "YROTATION" - } + ], + "title": "touschek" + }, + "_NAME": "command_touschek" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_twiss.line", + "command_twiss.range", + "command_twiss.deltap", + "command_twiss.chrom", + "command_twiss.centre", + "command_twiss.tolerance", + "command_twiss.file", + "command_twiss.rmatrix", + "command_twiss.sectormap", + "command_twiss.sectortable", + "command_twiss.sectorfile", + "command_twiss.sectorpure", + "command_twiss.keeporbit", + "command_twiss.useorbit", + "command_twiss.ripken", + "command_twiss.betx", + "command_twiss.alfx", + "command_twiss.mux", + "command_twiss.dx", + "command_twiss.dpx", + "command_twiss.bety", + "command_twiss.muy", + "command_twiss.alfy", + "command_twiss.dy", + "command_twiss.dpy", + "command_twiss.x", + "command_twiss.px", + "command_twiss.y", + "command_twiss.py", + "command_twiss.t", + "command_twiss.pt", + "command_twiss.wx", + "command_twiss.phix", + "command_twiss.dmux", + "command_twiss.ddx", + "command_twiss.ddpx", + "command_twiss.wy", + "command_twiss.phiy", + "command_twiss.dmuy", + "command_twiss.ddy", + "command_twiss.ddpy", + "command_twiss.r11", + "command_twiss.r12", + "command_twiss.r21", + "command_twiss.r22" + ] + } + } + ], + "title": "twiss" + }, + "_NAME": "command_twiss" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_use.sequence", + "command_use.period" + ] + } + } + ], + "title": "use" + }, + "_NAME": "command_use" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_vary.name", + "command_vary.step", + "command_vary.lower", + "command_vary.upper", + "command_vary.slope", + "command_vary.opt" + ] + } + } + ], + "title": "vary" + }, + "_NAME": "command_vary" + } + ] ] } From 386186afde51969a9c84f1bde1cb1d02db59ef37 Mon Sep 17 00:00:00 2001 From: garsuga Date: Mon, 1 May 2023 22:33:37 +0000 Subject: [PATCH 38/68] add autosave middleware, being lattice --- react/src/component/reusable/navbar.scss | 3 +- react/src/data/middleware/middleware.ts | 5 +- react/src/data/middleware/save.ts | 29 ++ react/src/layout/input/enum.tsx | 4 +- react/src/layout/madx/lattice.tsx | 114 +++++ react/src/layout/navbar.tsx | 2 +- react/src/layout/panel.tsx | 120 +++-- .../package_data/static/js/sirepo-lattice.js | 478 +++++++++--------- .../static/react-json/madx-schema.json | 48 +- 9 files changed, 457 insertions(+), 346 deletions(-) create mode 100644 react/src/data/middleware/save.ts create mode 100644 react/src/layout/madx/lattice.tsx diff --git a/react/src/component/reusable/navbar.scss b/react/src/component/reusable/navbar.scss index 2b699aa7d5..8e21b41dd9 100644 --- a/react/src/component/reusable/navbar.scss +++ b/react/src/component/reusable/navbar.scss @@ -5,9 +5,10 @@ .sr-navbar-container { display: flex; flex-flow: row nowrap; - width: 100%; padding-left: 10px; align-items: center; + flex-grow: 1; + justify-content: space-between; } .sr-navbar { diff --git a/react/src/data/middleware/middleware.ts b/react/src/data/middleware/middleware.ts index 0c38402ea1..b4c60d5eba 100644 --- a/react/src/data/middleware/middleware.ts +++ b/react/src/data/middleware/middleware.ts @@ -1,5 +1,6 @@ import { Middleware } from "redux"; import { Schema } from "../../utility/schema"; +import { saveMiddleware } from "./save"; import { shadowBeamlineSortingMiddleware } from "./shadow/beamline"; import { shadowBeamlineWatchpointReportsMiddleware } from "./shadow/watchpoint"; @@ -7,10 +8,10 @@ export type ConfigurableMiddleware = (config: C, schema: Schema) => Middlewar export const Middlewares: {[key: string]: ConfigurableMiddleware} = { shadowWatchpointsFromBeamline: shadowBeamlineWatchpointReportsMiddleware, - shadowBeamlineSorting: shadowBeamlineSortingMiddleware + shadowBeamlineSorting: shadowBeamlineSortingMiddleware, + save: saveMiddleware } export function middlewaresForSchema(schema: Schema): Middleware[] { - console.log("schema middleware", schema.middleware); return (schema.middleware || []).map(sm => Middlewares[sm.type](sm.config, schema)); } diff --git a/react/src/data/middleware/save.ts b/react/src/data/middleware/save.ts new file mode 100644 index 0000000000..3a2f452cd7 --- /dev/null +++ b/react/src/data/middleware/save.ts @@ -0,0 +1,29 @@ +import { ConfigurableMiddleware } from "./middleware" + +export type SaveMiddlewareConfig = { + minIntervalSeconds: number, + maxIntervalSeconds: number +} + +export const saveMiddleware: ConfigurableMiddleware = (config, schema) => { + let saveTimeout = undefined; + let firstUpdateInSave = undefined; + return store => next => action => { + if(action.type === "models/updateModel") { + if(firstUpdateInSave === undefined) { + firstUpdateInSave = Date.now(); + } + if(saveTimeout !== undefined) { + clearTimeout(saveTimeout); + } + + let timeUntilSave = Math.min(config.minIntervalSeconds, Math.min(0, config.maxIntervalSeconds - (Date.now() - firstUpdateInSave) / 1000)) + + saveTimeout = setTimeout(() => { + firstUpdateInSave = undefined; + + }, timeUntilSave) + } + return next(action); + } +} diff --git a/react/src/layout/input/enum.tsx b/react/src/layout/input/enum.tsx index 674c1901eb..ab8af8a87c 100644 --- a/react/src/layout/input/enum.tsx +++ b/react/src/layout/input/enum.tsx @@ -89,7 +89,7 @@ export class ArrayElementEnumInputLayout extends InputLayout { + let optionValues = ((depHandle.value || []) as any[]).map(x => x.item).map(rv => { return { display: `${rv[this.config.displayFieldName || this.config.valueFieldName]}`, value: `${rv[this.config.valueFieldName]}` @@ -106,7 +106,7 @@ export class ArrayElementEnumInputLayout extends InputLayout ( - )); diff --git a/react/src/layout/madx/lattice.tsx b/react/src/layout/madx/lattice.tsx new file mode 100644 index 0000000000..37e6107dbb --- /dev/null +++ b/react/src/layout/madx/lattice.tsx @@ -0,0 +1,114 @@ +import { ClipPath } from "@visx/visx"; +import { Zoom } from "@visx/zoom"; +import React, { useRef } from "react"; +import { FunctionComponent } from "react"; +import { useGraphContentBounds } from "../../utility/component"; +import { Layout } from "../layout"; + +export type LatticeConfig = {} + +export class LatticeLayout extends Layout { + component: FunctionComponent<{ [key: string]: any; }> = (props) => { + const ref = useRef(null); + const gc = useGraphContentBounds(ref, 9 / 16.0); + + return ( +
+ + width={gc.width} + height={gc.height}> + {(zoom) => { + let clipId = `graph-clip${Math.random()}`; + return ( + + + { + + } + + ) + }} + +
+ + ) + } +} + +type BeamlineSettings = { + flatten: boolean +} + +type BeamlineElementProps = { + children?: React.ReactNode, + type: string, + settings: BeamlineSettings +} & T + +const BeamlineElements: {[key: string]: FunctionComponent} = { + /*bend: (props: BeamlineElementProps<{angle: number, length: number, enterEdge: number, exitEdge: number}>) => { + var points = [ + [enter[0] - Math.sin(-enterEdge) * height / 2, + enter[1] - Math.cos(-enterEdge) * height / 2], + [enter[0] + Math.sin(-enterEdge) * height / 2, + enter[1] + Math.cos(-enterEdge) * height / 2], + [exit[0] + Math.sin(exitAngle) * height / 2, + exit[1] + Math.cos(exitAngle) * height / 2], + [exit[0] - Math.sin(exitAngle) * height / 2, + exit[1] - Math.cos(exitAngle) * height / 2], + ]; + // trim overlap if necessary + if (length >= 0) { + if (points[1][0] > points[2][0]) { + points[1] = points[2] = lineIntersection(points); + } + else if (points[0][0] > points[3][0]) { + points[0] = points[3] = lineIntersection(points); + } + } + else { + if (points[1][0] < points[2][0]) { + points[1] = points[2] = lineIntersection(points); + } + else if (points[0][0] < points[3][0]) { + points[0] = points[3] = lineIntersection(points); + } + } + + + return ( + + + + + + ) + }*/ +} + +// TODO: real implementation +const rpnValue = (x) => x; + +function degreesToRadians(deg): number { + return deg * Math.PI / 180; +} + +function latticeFromData() { + let rotate = (angle, x, y) => { + var radAngle = degreesToRadians(angle); + return { + x: rpnValue(x) * Math.cos(radAngle) - rpnValue(y) * Math.sin(radAngle), + y: rpnValue(x) * Math.sin(radAngle) + rpnValue(y) * Math.cos(radAngle) + } + } + + let itemTrackHash = (item, group, length, angle) => { + return group.items.length + '-' + item.name + '-' + item._id + '-' + length + '-' + + group.rotate + '-' + group.rotateX + '-' + group.rotateY + '-' + (angle || 0) + + '-' + item.beamlineIndex + '-' + (item.elemedge || 0) + + '-' + (item.open_side || ''); + } +} diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index 19ad1c7132..e392fd2c33 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -150,7 +150,7 @@ export class NavTabsLayout extends Layout { return ( <> -
`, - controller: function($scope) { + controller: function ($scope) { $scope.latticeService = latticeService; $scope.tooltip = SIREPO.lattice.beamlineEditorTooltip; $scope.beamlineItems = []; @@ -687,7 +687,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS function cache(id) { if (itemCache[id] === undefined) { const res = latticeService.elementForId(id); - if (! res) { + if (!res) { throw new Error('Invalid element id: ' + id); } itemCache[id] = res; @@ -698,10 +698,10 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS $scope.itemCache = cache; function getPosition(idx) { - if (! activeBeamline.positions) { + if (!activeBeamline.positions) { activeBeamline.positions = []; } - if (! activeBeamline.positions[idx]) { + if (!activeBeamline.positions[idx]) { activeBeamline.positions[idx] = {}; } return activeBeamline.positions[idx]; @@ -766,7 +766,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS else { x = Math.round( (rpnService.getRpnValue(pos.elemedge) + rpnService.getRpnValue(el.l || 0)) - * 1e7) / 1e7; + * 1e7) / 1e7; } } getPosition(index).elemedge = x; @@ -782,7 +782,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS function setPosition(popupName, fields) { $scope.clearPopover(); - if (! latticeService.selectedItem) { + if (!latticeService.selectedItem) { return; } let idx = itemIndex(latticeService.selectedItem); @@ -821,7 +821,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS function showPopover(item, popoverName) { activePopoverName = popoverName; let info = $scope.popoverInfo[popoverName]; - if (! info.content) { + if (!info.content) { // keep a single reference to prevent garbage collection when dismissed? info.content = $('.' + info.class); } @@ -842,7 +842,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS function showPopoverForItem(item) { panelState.waitForUI(() => { - if (! item.isBeamline && latticeService.isAbsolutePositioning()) { + if (!item.isBeamline && latticeService.isAbsolutePositioning()) { panelState.waitForUI(() => showElementPositionPopover(item)); } }); @@ -871,7 +871,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS $scope.selectItem(item, $event); if (latticeService.isAbsolutePositioning()) { $('.sr-lattice-item').not(getUIItem(item)).popover('hide'); - if (! item.isBeamline) { + if (!item.isBeamline) { showElementPositionPopover(item); } } @@ -957,7 +957,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS }; $scope.dropItem = (index, data) => { - if (! data || dragCanceled) { + if (!data || dragCanceled) { return; } $scope.clearPopover(); @@ -993,7 +993,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS }; $scope.dropPanel = (data) => { - if (! data + if (!data || data.itemId || data.id == activeBeamline.id || dragCanceled) { @@ -1011,7 +1011,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS updateBeamline(false); dropHandled = false; panelState.waitForUI(() => { - if (! dropHandled) { + if (!dropHandled) { $rootScope.$broadcast('sr-beamlineDropItem', item, $scope.beamlineItems); updateBeamline(true); showPopoverForItem(item); @@ -1029,7 +1029,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS $scope.editItem = (item) => { if (item.isBeamline) { - if (! latticeService.isAbsolutePositioning()) { + if (!latticeService.isAbsolutePositioning()) { showModifyBeamlinePopover(item); } } @@ -1070,7 +1070,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS $scope.onMouseDown = (item, $event) => { // right mouse button if ($event.buttons == 2 && item.isBeamline) { - if (! latticeService.isAbsolutePositioning()) { + if (!latticeService.isAbsolutePositioning()) { showModifyBeamlinePopover(item, $event); } } @@ -1078,7 +1078,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS $scope.reverseBeamline = () => { $scope.clearPopover(); - if (! latticeService.selectedItem || ! latticeService.selectedItem.isBeamline) { + if (!latticeService.selectedItem || !latticeService.selectedItem.isBeamline) { return; } let item = latticeService.selectedItem; @@ -1092,7 +1092,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS if ($scope.shiftClickHandler) { $scope.shiftClickHandler()(latticeService.selectedItem, item); } - else if (! latticeService.isAbsolutePositioning()) { + else if (!latticeService.isAbsolutePositioning()) { lastSelectedItem = item; $scope.newBeamline = latticeService.getNextBeamline(); $('#sr-beamline-from-elements-dialog').modal('show'); @@ -1114,7 +1114,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS }; $scope.showEditor = () => { - if (! appState.isLoaded() || ! latticeService.activeBeamlineId) { + if (!appState.isLoaded() || !latticeService.activeBeamlineId) { return false; } let beamline = latticeService.getActiveBeamline(); @@ -1134,7 +1134,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS $scope.unpackBeamline = () => { $scope.clearPopover(); - if (! latticeService.selectedItem || ! latticeService.selectedItem.isBeamline) { + if (!latticeService.selectedItem || !latticeService.selectedItem.isBeamline) { return; } let idx = $scope.beamlineItems.indexOf(latticeService.selectedItem); @@ -1177,7 +1177,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS (e, beamlineIndex) => $scope.selectItem($scope.beamlineItems[beamlineIndex])); $scope.$on('sr-beamlineOrderChanged', reloadBeamlineItems); }, - link: function(scope, element) { + link: function (scope, element) { scope.element = $(element).find('.sr-lattice-editor-panel').first(); $document.on('keydown', scope.onKeyDown); scope.$on('$destroy', () => $document.off('keydown', scope.onKeyDown)); @@ -1185,7 +1185,7 @@ SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelS }; }); -SIREPO.app.directive('elementPicker', function(latticeService) { +SIREPO.app.directive('elementPicker', function (latticeService) { return { restrict: 'A', scope: { @@ -1241,17 +1241,17 @@ SIREPO.app.directive('elementPicker', function(latticeService) {
`, - controller: function($scope) { + controller: function ($scope) { $scope.activeTab = 'basic'; $scope.allNames = $scope.controller.basicNames.concat($scope.controller.advancedNames).sort(); $scope.showTabs = $scope.controller.advancedNames.length > 0; - $scope.createElement = function(name) { + $scope.createElement = function (name) { // don't show the new editor until the picker panel is gone // the modal show/hide in bootstrap doesn't handle layered modals // and the browser scrollbar can be lost in some cases var picker = $('#' + $scope.id); - picker.on('hidden.bs.modal', function() { + picker.on('hidden.bs.modal', function () { picker.off(); if ($scope.controller.createElement) { $scope.controller.createElement(name); @@ -1267,7 +1267,7 @@ SIREPO.app.directive('elementPicker', function(latticeService) { }; }); -SIREPO.app.directive('parameterWithLattice', function(appState) { +SIREPO.app.directive('parameterWithLattice', function (appState) { return { restrict: 'A', scope: { @@ -1281,13 +1281,13 @@ SIREPO.app.directive('parameterWithLattice', function(appState) {
`, - controller: function($scope, $element) { + controller: function ($scope, $element) { var latticeScope, plotScope; var isNestedSVG = false; function updateLattice() { if ($scope.showLattice() && latticeScope && plotScope) { - if (! isNestedSVG) { + if (!isNestedSVG) { // nest the SVG so the "download as png" gets both images isNestedSVG = true; var svgs = $($element).find('svg'); @@ -1302,10 +1302,10 @@ SIREPO.app.directive('parameterWithLattice', function(appState) { } } - $scope.showLattice = function() { + $scope.showLattice = function () { if (appState.isLoaded()) { if (appState.applicationState()[$scope.modelName].includeLattice == '1') { - if (plotScope && ! plotScope.onRefresh) { + if (plotScope && !plotScope.onRefresh) { plotScope.onRefresh = updateLattice; } return true; @@ -1318,12 +1318,12 @@ SIREPO.app.directive('parameterWithLattice', function(appState) { return false; }; - $scope.$on('sr-latticeLinked', function(event) { + $scope.$on('sr-latticeLinked', function (event) { latticeScope = event.targetScope; event.stopPropagation(); updateLattice(); }); - $scope.$on('sr-plotLinked', function(event) { + $scope.$on('sr-plotLinked', function (event) { if (event.targetScope.focusPoints) { plotScope = event.targetScope; event.stopPropagation(); @@ -1333,7 +1333,7 @@ SIREPO.app.directive('parameterWithLattice', function(appState) { }; }); -SIREPO.app.directive('lattice', function(appState, latticeService, panelState, plotting, rpnService, utilities, $rootScope, $window) { +SIREPO.app.directive('lattice', function (appState, latticeService, panelState, plotting, rpnService, utilities, $rootScope, $window) { return { restrict: 'A', scope: { @@ -1344,7 +1344,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p showTable: '@', }, templateUrl: '/static/html/lattice.html' + SIREPO.SOURCE_CACHE_KEY, - controller: function($scope) { + controller: function ($scope) { let panTranslate = [0, 0]; let picTypeCache = null; let selectedBeamline = null; @@ -1383,7 +1383,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p function subScaleWatch() { var xsMax = 50; return { - x: ($scope.xScale > xsMax ? xsMax / $scope.xScale : 1), + x: ($scope.xScale > xsMax ? xsMax / $scope.xScale : 1), y: 1, }; } @@ -1486,17 +1486,17 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p exitEdge = 0; } var exit = [enter[0] + radius + Math.cos(angle) * radius, - pos.y + Math.sin(angle) * radius]; + pos.y + Math.sin(angle) * radius]; var exitAngle = exitEdge - angle; var points = [ - [enter[0] - Math.sin(-enterEdge) * height / 2, - enter[1] - Math.cos(-enterEdge) * height / 2], - [enter[0] + Math.sin(-enterEdge) * height / 2, - enter[1] + Math.cos(-enterEdge) * height / 2], - [exit[0] + Math.sin(exitAngle) * height / 2, - exit[1] + Math.cos(exitAngle) * height / 2], - [exit[0] - Math.sin(exitAngle) * height / 2, - exit[1] - Math.cos(exitAngle) * height / 2], + [enter[0] - Math.sin(-enterEdge) * height / 2, + enter[1] - Math.cos(-enterEdge) * height / 2], + [enter[0] + Math.sin(-enterEdge) * height / 2, + enter[1] + Math.cos(-enterEdge) * height / 2], + [exit[0] + Math.sin(exitAngle) * height / 2, + exit[1] + Math.cos(exitAngle) * height / 2], + [exit[0] - Math.sin(exitAngle) * height / 2, + exit[1] - Math.cos(exitAngle) * height / 2], ]; // trim overlap if necessary if (length >= 0) { @@ -1526,10 +1526,10 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p x += radius; newAngle = latticeService.radiansToDegrees(angle); pos.radius = radius; - if (item.type == 'CHANGREF' && ! $scope.flatten) { + if (item.type == 'CHANGREF' && !$scope.flatten) { adjustPosition(pos, item.XCE, -item.YCE); } - else if (item.type == 'CHANGREF_VALUE' && ! $scope.flatten) { + else if (item.type == 'CHANGREF_VALUE' && !$scope.flatten) { if (item.transformType == 'XS') { adjustPosition(pos, item.transformValue, 0); } @@ -1629,7 +1629,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p } } else if (picType == 'magnet') { - if (! length) { + if (!length) { groupItem.height = 0.2; groupItem.y = pos.y; groupItem.picType = 'zeroLength'; @@ -1668,7 +1668,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p groupItem.y = pos.y; //TODO(pjm): special zgoubi type, shift Y/Z axis 180 if (item.type == 'YMY') { - pos.inReverseBend = ! pos.inReverseBend; + pos.inReverseBend = !pos.inReverseBend; } } else if (picType == 'rf') { @@ -1736,7 +1736,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p if ($scope.flatten) { newAngle = 0; } - group.trackHash = $scope.svgGroups.length + ' ' + group.items.map(function(item) { + group.trackHash = $scope.svgGroups.length + ' ' + group.items.map(function (item) { return item.trackHash; }).join(' '); pos.angle += newAngle; @@ -1746,9 +1746,9 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p if (items.indexOf(id) >= 0) { return true; } - if (! beamlineCache) { + if (!beamlineCache) { beamlineCache = {}; - $scope.models.beamlines.forEach(function(b) { + $scope.models.beamlines.forEach(function (b) { beamlineCache[b.id] = b.items; }); } @@ -1775,8 +1775,8 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p function calculateInitialBeamlineMetrics() { // when lattice is initially loaded after import, calculate stats for all beamlines var beamlines = $scope.models.beamlines; - if (beamlines.length && ! angular.isDefined(beamlines[0].count)) { - beamlines.forEach(function(beamline) { + if (beamlines.length && !angular.isDefined(beamlines[0].count)) { + beamlines.forEach(function (beamline) { loadItemsFromBeamline(true, beamline); }); } @@ -1834,7 +1834,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p //TODO(pjm): will infinitely recurse if beamlines are self-referential function explodeItems(beamline, res, reversed, beamlineIndex) { var items = beamline.items; - if (! res) { + if (!res) { res = []; } if (reversed) { @@ -1879,7 +1879,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p } function getPicType(type) { - if (! picTypeCache) { + if (!picTypeCache) { picTypeCache = {}; var elementPic = SIREPO.lattice.elementPic; for (var picType in elementPic) { @@ -1925,11 +1925,11 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p beamline = beamline || ($scope.flatten && $scope.modelName != 'twissReport' ? latticeService.getSimulationBeamline() : latticeService.getActiveBeamline()); - if (! beamline) { + if (!beamline) { selectedBeamline = null; return; } - if (! forceUpdate && selectedBeamline + if (!forceUpdate && selectedBeamline && appState.deepEquals(beamline.items, selectedBeamline.items) && appState.deepEquals(beamline.positions, selectedBeamline.positions)) { return; @@ -1937,7 +1937,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p selectedBeamline = appState.clone(beamline); $scope.svgGroups = []; var pos = computePositions(); - if (! $scope.flatten && beamlineValue(beamline, 'distance', Math.sqrt(Math.pow(pos.x, 2) + Math.pow(pos.y, 2))) + if (!$scope.flatten && beamlineValue(beamline, 'distance', Math.sqrt(Math.pow(pos.x, 2) + Math.pow(pos.y, 2))) + beamlineValue(beamline, 'length', pos.length) + beamlineValue(beamline, 'angle', latticeService.degreesToRadians(pos.angle)) + beamlineValue(beamline, 'count', pos.count)) { @@ -2027,16 +2027,16 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p $scope.$broadcast('sr-renderBeamline'); } - $scope.destroy = function() { + $scope.destroy = function () { if (zoom) { zoom.on('zoom', null); } }; - $scope.init = function() { + $scope.init = function () { zoom = d3.behavior.zoom() .scaleExtent([1, 50]); - if (! $scope.flatten) { + if (!$scope.flatten) { zoom.on('zoom', zoomed); //TODO(pjm): call stopPropagation() on item double-click instead, would allow double-click zoom on empty space select('svg').call(zoom) @@ -2045,15 +2045,15 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p $scope.resize(); }; - $scope.itemClicked = function(item) { + $scope.itemClicked = function (item) { $rootScope.$broadcast('sr-beamlineItemSelected', item.beamlineIndex); }; - $scope.itemDblClicked = function(item) { + $scope.itemDblClicked = function (item) { latticeService.editElement(item.type, item, $scope.models); }; - $scope.resize = function() { + $scope.resize = function () { if (select().empty()) { return; } @@ -2100,8 +2100,8 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p } }; - $scope.updateFixedAxis = function(axis, leftMargin, yScale, height, yOffset) { - if (! axis.domain) { + $scope.updateFixedAxis = function (axis, leftMargin, yScale, height, yOffset) { + if (!axis.domain) { return; } var widthInPixels = axis.scale.range()[1]; @@ -2123,13 +2123,13 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p } // only show the loading message for simulations with a lot of elements $scope.isLoading = $scope.models.elements.length > 25; - panelState.waitForUI(function() { + panelState.waitForUI(function () { $scope.isLoading = false; loadItemsFromBeamline(forceUpdate); }); } - appState.whenModelsLoaded($scope, function() { + appState.whenModelsLoaded($scope, function () { function getModels() { $scope.models = $scope.pathToModels ? appState.models[$scope.pathToModels].models : appState.models; } @@ -2138,12 +2138,12 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p calculateInitialBeamlineMetrics(); renderBeamline(); - $scope.$on($scope.pathToModels + '.changed', function(e, name) { + $scope.$on($scope.pathToModels + '.changed', function (e, name) { getModels(); renderBeamline(true); }); - $scope.$on('modelChanged', function(e, name) { + $scope.$on('modelChanged', function (e, name) { if (name == 'beamlines') { renderBeamline(); } @@ -2159,7 +2159,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p $scope.$on('cancelChanges', getModels); - $scope.$on('activeBeamlineChanged', function($event, updateNoWait) { + $scope.$on('activeBeamlineChanged', function ($event, updateNoWait) { renderBeamline(false, updateNoWait); resetZoomAndPan(); }); @@ -2172,7 +2172,7 @@ SIREPO.app.directive('lattice', function(appState, latticeService, panelState, p }; }); -SIREPO.app.directive('latticeBeamlineList', function(appState) { +SIREPO.app.directive('latticeBeamlineList', function (appState) { return { restrict: 'A', scope: { @@ -2183,22 +2183,22 @@ SIREPO.app.directive('latticeBeamlineList', function(appState) { template: ` `, - controller: function($scope) { + controller: function ($scope) { var list = [ { id: '', name: 'NOT SELECTED', }, ]; - $scope.beamlineList = function() { - if (! appState.isLoaded() || ! $scope.model) { + $scope.beamlineList = function () { + if (!appState.isLoaded() || !$scope.model) { return null; } if ($scope.isOptional) { list.length = 1; return list.concat(appState.models.beamlines); } - if (! $scope.model[$scope.field] + if (!$scope.model[$scope.field] && appState.models.beamlines && appState.models.beamlines.length) { $scope.model[$scope.field] = appState.models.beamlines[0].id; @@ -2209,7 +2209,7 @@ SIREPO.app.directive('latticeBeamlineList', function(appState) { }; }); -SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, panelState, $window) { +SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, panelState, $window) { return { restrict: 'A', scope: {}, @@ -2257,7 +2257,7 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, `, - controller: function($scope) { + controller: function ($scope) { $scope.appState = appState; $scope.latticeService = latticeService; var windowSize = 0; @@ -2266,7 +2266,7 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, function computeNesting() { isNested = {}; - appState.models.beamlines.forEach(function(beamline) { + appState.models.beamlines.forEach(function (beamline) { computeNestingBeamline(beamline); }); } @@ -2276,20 +2276,20 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, return; } var activeBeamline = latticeService.getActiveBeamline(); - if(! activeBeamline || activeBeamline.id === beamline.id) { + if (!activeBeamline || activeBeamline.id === beamline.id) { isNested[beamline.id] = true; return; } - if(! blItems) { + if (!blItems) { blItems = beamline.items || []; } - if(blItems.indexOf(activeBeamline.id) >= 0) { + if (blItems.indexOf(activeBeamline.id) >= 0) { isNested[beamline.id] = true; return; } - for(var i = 0; i < blItems.length; i++) { + for (var i = 0; i < blItems.length; i++) { var nextItems = latticeService.elementForId(blItems[i]).items; - if(nextItems && computeNestingBeamline(beamline, nextItems)) { + if (nextItems && computeNestingBeamline(beamline, nextItems)) { isNested[beamline.id] = true; return; } @@ -2298,7 +2298,7 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, function itemsToString(items) { var res = '('; - if (! items.length) { + if (!items.length) { res += ' '; } for (var i = 0; i < items.length; i++) { @@ -2316,10 +2316,10 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, windowSize = $($window).width(); } - $scope.copyBeamline = function(beamline) { + $scope.copyBeamline = function (beamline) { var newBeamline = latticeService.getNextBeamline(); - for(var prop in beamline) { - if(prop != 'id' && prop != 'name' && prop != 'items') { + for (var prop in beamline) { + if (prop != 'id' && prop != 'name' && prop != 'items') { newBeamline[prop] = beamline[prop]; } } @@ -2328,14 +2328,14 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, panelState.showModalEditor('beamline'); }; - $scope.beamlineBend = function(beamline, defaultValue) { + $scope.beamlineBend = function (beamline, defaultValue) { if (angular.isDefined(beamline.angle)) { return latticeService.angleFormat(beamline.angle); } return defaultValue; }; - $scope.beamlineDescription = function(beamline) { + $scope.beamlineDescription = function (beamline) { if (descriptionCache[beamline.id]) { return descriptionCache[beamline.id]; } @@ -2344,26 +2344,26 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, return res; }; - $scope.beamlineDistance = function(beamline) { + $scope.beamlineDistance = function (beamline) { return latticeService.numFormat(beamline.distance, 'm'); }; - $scope.beamlineLength = function(beamline) { + $scope.beamlineLength = function (beamline) { return latticeService.numFormat(beamline.length, 'm'); }; - $scope.deleteBeamline = function(beamline) { + $scope.deleteBeamline = function (beamline) { latticeService.deleteElementPrompt('beamlines', beamline); }; - $scope.isActiveBeamline = function(beamline) { + $scope.isActiveBeamline = function (beamline) { if (latticeService.activeBeamlineId) { return latticeService.activeBeamlineId == beamline.id; } return false; }; - $scope.isLargeWindow = function() { + $scope.isLargeWindow = function () { return windowSize >= 1200; }; @@ -2371,16 +2371,16 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, return isNested[beamline.id]; }; - appState.whenModelsLoaded($scope, function() { - $scope.$on('beamlines.changed', function() { + appState.whenModelsLoaded($scope, function () { + $scope.$on('beamlines.changed', function () { computeNesting(); descriptionCache = {}; }); - $scope.$on('elements.changed', function() { + $scope.$on('elements.changed', function () { descriptionCache = {}; }); $scope.$on('activeBeamlineChanged', computeNesting); - $scope.$on('sr-window-resize', windowResize); + $scope.$on('sr-window-resize', windowResize); computeNesting(); windowResize(); }); @@ -2388,7 +2388,7 @@ SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, }; }); -SIREPO.app.directive('latticeElementPanels', function(latticeService) { +SIREPO.app.directive('latticeElementPanels', function (latticeService) { return { restrict: 'A', scope: {}, @@ -2415,13 +2415,13 @@ SIREPO.app.directive('latticeElementPanels', function(latticeService) { `, - controller: function($scope) { + controller: function ($scope) { $scope.latticeService = latticeService; }, }; }); -SIREPO.app.directive('latticeElementTable', function(appState, latticeService, panelState, $rootScope) { +SIREPO.app.directive('latticeElementTable', function (appState, latticeService, panelState, $rootScope) { return { restrict: 'A', scope: {}, @@ -2468,7 +2468,7 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p `, - controller: function($scope) { + controller: function ($scope) { $scope.latticeService = latticeService; $scope.tree = []; var collapsedElements = {}; @@ -2476,8 +2476,8 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p function areAllExpanded() { if (appState.models.treeMap) { - for (const k in appState.models.treeMap){ - if (appState.models.treeMap[k]){ + for (const k in appState.models.treeMap) { + if (appState.models.treeMap[k]) { return false; } } @@ -2496,7 +2496,7 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p } function elementDescription(element) { - if (! element) { + if (!element) { return 'null'; } if (angular.isDefined(descriptionCache[element._id])) { @@ -2536,7 +2536,7 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p return res; } - function getCollapsedMap(){ + function getCollapsedMap() { const m = {}; $scope.tree.forEach((e) => { m[e.name] = e.isCollapsed; @@ -2545,15 +2545,15 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p } function scrollToElem(found) { - if (found){ + if (found) { panelState.waitForUI(() => { - $('.sr-search-target')[0].scrollIntoView({block: 'center'}); + $('.sr-search-target')[0].scrollIntoView({ block: 'center' }); }); } } function getIsCollapsed(elType) { - if (appState.models.treeMap){ + if (appState.models.treeMap) { return appState.models.treeMap[elType]; } return false; @@ -2563,8 +2563,8 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p $scope.tree = []; descriptionCache = {}; var category = null; - appState.applicationState().elements.forEach(function(element) { - if (! category || category.name != element.type) { + appState.applicationState().elements.forEach(function (element) { + if (!category || category.name != element.type) { category = { name: element.type, elements: [], @@ -2582,30 +2582,30 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p appState.saveQuietly('treeMap'); } - $scope.deleteElement = function(element) { + $scope.deleteElement = function (element) { latticeService.deleteElementPrompt('elements', element); }; - $scope.editElement = function(type, item) { + $scope.editElement = function (type, item) { var el = latticeService.elementForId(item._id); return latticeService.editElement(type, el); }; $scope.copyElement = el => latticeService.copyElement(el); - $scope.elementLength = function(element) { + $scope.elementLength = function (element) { return latticeService.numFormat(element.l, 'm'); }; $scope.findElement = (el) => { - if (!el){ + if (!el) { return; } let found = false; let foundIndex = null; $scope.tree.forEach((t, i) => { t.elements.forEach((e, j) => { - if (e.name.toLowerCase().startsWith(el.toLowerCase()) && el.length > 1){ + if (e.name.toLowerCase().startsWith(el.toLowerCase()) && el.length > 1) { foundIndex = i; $scope.tree[i].elements[j].isMarked = true; found = true; @@ -2613,7 +2613,7 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p $scope.tree[i].elements[j].isMarked = false; } }); - if (i == foundIndex){ + if (i == foundIndex) { $scope.tree[i].isCollapsed = false; } else { $scope.tree[i].isCollapsed = true; @@ -2625,29 +2625,29 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p scrollToElem(found); }; - $scope.toggleCategory = function(category) { - category.isCollapsed = ! category.isCollapsed; + $scope.toggleCategory = function (category) { + category.isCollapsed = !category.isCollapsed; collapsedElements[category.name] = category.isCollapsed; appState.models.treeMap = getCollapsedMap(); appState.saveChanges('treeMap'); }; $scope.toggleCollapseElems = () => { - $scope.areAllExpanded = ! $scope.areAllExpanded; + $scope.areAllExpanded = !$scope.areAllExpanded; $scope.tree.forEach(e => { - e.isCollapsed = ! $scope.areAllExpanded; + e.isCollapsed = !$scope.areAllExpanded; }); appState.models.treeMap = getCollapsedMap(); appState.saveChanges('treeMap'); }; - $scope.$on('modelChanged', function(e, name) { + $scope.$on('modelChanged', function (e, name) { if (name == 'elements') { loadTree(); } }); - $scope.$on('elementDeleted', function(e, name) { + $scope.$on('elementDeleted', function (e, name) { if (name == 'elements') { loadTree(); } @@ -2657,7 +2657,7 @@ SIREPO.app.directive('latticeElementTable', function(appState, latticeService, p }; }); -SIREPO.app.directive('latticeTab', function(latticeService, panelState, utilities, $window) { +SIREPO.app.directive('latticeTab', function (latticeService, panelState, utilities, $window) { return { restrict: 'A', scope: { @@ -2714,7 +2714,7 @@ SIREPO.app.directive('latticeTab', function(latticeService, panelState, utilitie `, - controller: function($scope) { + controller: function ($scope) { $scope.reportId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); $scope.latticeService = latticeService; @@ -2722,42 +2722,42 @@ SIREPO.app.directive('latticeTab', function(latticeService, panelState, utilitie return SIREPO.APP_SCHEMA.model.twissReport ? true : false; } - $scope.showTwissReportButton = function() { + $scope.showTwissReportButton = function () { if (hasTwissReport()) { var beamline = latticeService.getActiveBeamline(); return beamline && beamline.length != 0; } return false; }; - $scope.showTwissReport = function() { + $scope.showTwissReport = function () { if (utilities.isFullscreen()) { utilities.exitFullscreenFn().call(document); } var el = $('#sr-lattice-twiss-plot'); el.modal('show'); - el.on('shown.bs.modal', function() { + el.on('shown.bs.modal', function () { $scope.twissReportShown = true; $scope.$digest(); }); - el.on('hidden.bs.modal', function() { + el.on('hidden.bs.modal', function () { $scope.twissReportShown = false; el.off(); }); }; - $scope.twissReportTitle = function() { + $scope.twissReportTitle = function () { if (hasTwissReport()) { return SIREPO.APP_SCHEMA.view.twissReport.title; } return ''; }; - $scope.showTwissEditor = function() { + $scope.showTwissEditor = function () { panelState.showModalEditor('twissReport'); }; }, }; }); -SIREPO.app.directive('rpnBoolean', function(rpnService) { +SIREPO.app.directive('rpnBoolean', function (rpnService) { return { restrict: 'A', scope: { @@ -2767,15 +2767,15 @@ SIREPO.app.directive('rpnBoolean', function(rpnService) { template: ` `, - controller: function($scope) { - $scope.rpnBooleanValues = function() { + controller: function ($scope) { + $scope.rpnBooleanValues = function () { return rpnService.getRpnBooleanForField($scope.model, $scope.field); }; }, }; }); -SIREPO.app.directive('rpnStatic', function(rpnService) { +SIREPO.app.directive('rpnStatic', function (rpnService) { return { restrict: 'A', scope: { @@ -2787,8 +2787,8 @@ SIREPO.app.directive('rpnStatic', function(rpnService) { template: `
{{ computedRpnValue(); }}
`, - controller: function($scope) { - $scope.computedRpnValue = function() { + controller: function ($scope) { + $scope.computedRpnValue = function () { if ($scope.isBusy) { return 'calculating...'; } @@ -2800,7 +2800,7 @@ SIREPO.app.directive('rpnStatic', function(rpnService) { }; }); -SIREPO.app.directive('rpnEditor', function() { +SIREPO.app.directive('rpnEditor', function () { return { restrict: 'A', template: ` @@ -2811,26 +2811,26 @@ SIREPO.app.directive('rpnEditor', function() {
`, - controller: function($scope) { + controller: function ($scope) { $scope.isBusy = false; $scope.isError = false; }, }; }); -SIREPO.app.directive('rpnValue', function(appState, rpnService) { +SIREPO.app.directive('rpnValue', function (appState, rpnService) { var requestIndex = 0; return { restrict: 'A', require: 'ngModel', - link: function(scope, element, attrs, ngModel) { + link: function (scope, element, attrs, ngModel) { var rpnVariableName = scope.modelName == 'rpnVariable' ? scope.model.name : null; var range = { min: scope.info[4], max: scope.info[5], }; - scope.isRequired = function() { + scope.isRequired = function () { if (scope.info && scope.info[1] == 'OptionalRPNValue') { return false; } @@ -2842,7 +2842,7 @@ SIREPO.app.directive('rpnValue', function(appState, rpnService) { return true; }; - ngModel.$parsers.push(function(value) { + ngModel.$parsers.push(function (value) { scope.isError = false; requestIndex++; var currentRequestIndex = requestIndex; @@ -2866,21 +2866,21 @@ SIREPO.app.directive('rpnValue', function(appState, rpnService) { return v; } scope.isBusy = true; - rpnService.computeRpnValue(value, function(v, err) { + rpnService.computeRpnValue(value, function (v, err) { // check for a stale request if (requestIndex != currentRequestIndex) { return; } scope.isBusy = false; scope.isError = err ? true : false; - ngModel.$setValidity('', ! scope.isError); - if (rpnVariableName && ! err) { + ngModel.$setValidity('', !scope.isError); + if (rpnVariableName && !err) { rpnService.recomputeCache(rpnVariableName, v); } }); return value; }); - ngModel.$formatters.push(function(value) { + ngModel.$formatters.push(function (value) { if (ngModel.$isEmpty(value)) { return value; } @@ -2890,7 +2890,7 @@ SIREPO.app.directive('rpnValue', function(appState, rpnService) { }; }); -SIREPO.app.directive('varEditor', function(appState, latticeService, requestSender) { +SIREPO.app.directive('varEditor', function (appState, latticeService, requestSender) { return { scope: {}, template: ` @@ -2961,7 +2961,7 @@ SIREPO.app.directive('varEditor', function(appState, latticeService, requestSend `, - controller: function($scope, $element) { + controller: function ($scope, $element) { $scope.appState = appState; function initNewVar() { @@ -2974,12 +2974,12 @@ SIREPO.app.directive('varEditor', function(appState, latticeService, requestSend } function nameExists(name) { - return appState.models.rpnVariables.map(function(v) { + return appState.models.rpnVariables.map(function (v) { return v.name; }).indexOf(name) >= 0; } - $scope.addVar = function() { + $scope.addVar = function () { if ($scope.hasNewVar()) { var name = $scope.newVar.name; if (nameExists(name)) { @@ -2994,20 +2994,20 @@ SIREPO.app.directive('varEditor', function(appState, latticeService, requestSend } }; - $scope.cancelChanges = function() { + $scope.cancelChanges = function () { $('#sr-variables').modal('hide'); appState.cancelChanges('rpnVariables'); appState.cancelChanges('rpnCache'); initNewVar(); }; - $scope.deleteVar = function(idx) { + $scope.deleteVar = function (idx) { var v = appState.models.rpnVariables[idx]; requestSender.sendRpn( appState, - function(data) { + function (data) { latticeService.deleteVarWarning = ''; - if (! appState.isLoaded()) { + if (!appState.isLoaded()) { return; } if (data.error) { @@ -3024,7 +3024,7 @@ SIREPO.app.directive('varEditor', function(appState, latticeService, requestSend }); }; - $scope.hasNewVar = function() { + $scope.hasNewVar = function () { return 'name' in $scope.newVar && 'value' in $scope.newVar && $scope.newVar.name !== '' @@ -3035,7 +3035,7 @@ SIREPO.app.directive('varEditor', function(appState, latticeService, requestSend && $scope.newVar.value !== undefined; }; - $scope.saveChanges = function() { + $scope.saveChanges = function () { $('#sr-variables').modal('hide'); if ($scope.hasNewVar()) { $scope.addVar(); @@ -3049,16 +3049,16 @@ SIREPO.app.directive('varEditor', function(appState, latticeService, requestSend }; }); -SIREPO.app.directive('varName', function(latticeService) { +SIREPO.app.directive('varName', function (latticeService) { return { restrict: 'A', require: 'ngModel', scope: {}, - link: function(scope, element, attrs, ngModel) { + link: function (scope, element, attrs, ngModel) { var latticeNames; function isElementOrCommandName(value) { - if (! latticeNames) { + if (!latticeNames) { latticeNames = {}; for (var m in SIREPO.APP_SCHEMA.model) { if (latticeService.isElementModelName(m)) { @@ -3072,11 +3072,11 @@ SIREPO.app.directive('varName', function(latticeService) { return latticeNames[value.toLowerCase()]; } - ngModel.$parsers.push(function(value) { - if (ngModel.$isEmpty(value)) { + ngModel.$parsers.push(function (value) { + if (ngModel.$isEmpty(value)) { return null; } - if (! value.match(/^[A-Z][A-Z0-9_.]*$/i)) { + if (!value.match(/^[A-Z][A-Z0-9_.]*$/i)) { return undefined; } if ((SIREPO.APP_SCHEMA.constants.latticeKeywords || []).includes(value.toLowerCase())) { @@ -3096,7 +3096,7 @@ SIREPO.app.directive('varName', function(latticeService) { $(document).on('show.bs.modal', '.modal', function () { var zIndex = 1040 + (10 * $('.modal:visible').length); $(this).css('z-index', zIndex); - setTimeout(function() { + setTimeout(function () { $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'); }, 0); }); diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 9b85f108f6..3be7aa88fd 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -6402,25 +6402,6 @@ ] } }, - "OptionalBoolean": { - "base": "Enum", - "config": { - "allowedValues": [ - [ - "", - "NOT SELECTED" - ], - [ - "1", - "Yes" - ], - [ - "0", - "No" - ] - ] - } - }, "PtccreatelayoutModel": { "base": "Enum", "config": { @@ -6691,7 +6672,6 @@ "config": { "report": "bunchReport1", "dependencies": [ - "simulationSettings.*", "lattice.*", "elements.*", "bunch.*" @@ -6747,7 +6727,6 @@ "config": { "report": "bunchReport2", "dependencies": [ - "simulationSettings.*", "lattice.*", "elements.*", "bunch.*" @@ -6803,7 +6782,6 @@ "config": { "report": "bunchReport3", "dependencies": [ - "simulationSettings.*", "lattice.*", "elements.*", "bunch.*" @@ -6859,7 +6837,6 @@ "config": { "report": "bunchReport4", "dependencies": [ - "simulationSettings.*", "lattice.*", "elements.*", "bunch.*" @@ -6911,30 +6888,6 @@ } ] }, - { - "name": "control", - "title": "Control", - "items": [ - { - "layout": "waterfall", - "config": { - "breakpoints": { - "sm": 1, - "md": 2, - "xl": 3 - }, - "gutters": { - "horizontal": ".5em", - "vertical": ".5em" - }, - "padding": ".5em", - "items": [ - - ] - } - } - ] - }, { "name": "visualization", "title": "Visualization", @@ -7051,6 +7004,7 @@ } ] } + ] } } From 0533905f44f682793bf521806524e959af1c3ba4 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 2 May 2023 23:02:45 +0000 Subject: [PATCH 39/68] finish autosave middleware --- react/src/component/reusable/form.tsx | 4 +- react/src/component/simulation.tsx | 77 ++++++++----------- react/src/data/appwrapper.ts | 5 +- react/src/data/middleware/middleware.ts | 7 +- react/src/data/middleware/save.ts | 6 +- react/src/layout/panel.tsx | 6 +- .../static/react-json/common-schema.json | 9 +++ .../static/react-json/madx-schema.json | 2 +- 8 files changed, 58 insertions(+), 58 deletions(-) diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 939179ecb4..c5179bb6bb 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -64,9 +64,9 @@ export function formActionFunctions(config: { cancel: () => formHandleFactory.cancel(store.getState(), dispatch), submit: () => { formHandleFactory.save(store.getState(), dispatch); - simulationInfoPromise.then(simulationInfo => { + /*simulationInfoPromise.then(simulationInfo => { appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); - }) + })*/ } } } diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 7cd100c2b5..0ed733eb00 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -46,35 +46,17 @@ export type SimulationInfo = SimulationInfoRaw & { simulationId: string } -function SimulationStoreInitializer(props: {[key: string]: any}) { - let schema = useContext(CSchema); - - const [modelsStore, _] = useState(() => configureStore({ - reducer: { - [modelsSlice.name]: modelsSlice.reducer, - [formStatesSlice.name]: formStatesSlice.reducer, - }, - middleware: [...middlewaresForSchema(schema)] - })); - - return ( - - {props.children} - - ) -} - function SimulationInfoInitializer(props: { simulationId: string } & {[key: string]: any}) { let { simulationId } = props; - + let schema = useContext(CSchema); + + const [modelsStore, updateModelsStore] = useState(undefined); let [simulationInfoPromise, updateSimulationInfoPromise] = useState(undefined); let [hasInit, updateHasInit] = useState(false); let appName = useContext(CAppName); - let schema = useContext(CSchema); let routeHelper = useContext(CRouteHelper); - let dispatch = useDispatch(); useEffect(() => { updateSimulationInfoPromise(new Promise((resolve, reject) => { @@ -86,8 +68,18 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let simulationInfo = await resp.json(); let models = simulationInfo['models'] as ModelState[]; + let _store = configureStore({ + reducer: { + [modelsSlice.name]: modelsSlice.reducer, + [formStatesSlice.name]: formStatesSlice.reducer, + }, + middleware: [...middlewaresForSchema(schema, simulationInfo)] + }) + + updateModelsStore(_store) + for(let [modelName, model] of Object.entries(models)) { - dispatch(modelActions.updateModel({ + _store.dispatch(modelActions.updateModel({ name: modelName, value: model })) @@ -102,11 +94,13 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri let [handleFactory, _] = useCoupledState(schema, new BaseHandleFactory(schema)) return hasInit && simulationInfoPromise && ( - - - {props.children} - - + + + + {props.children} + + + ) } @@ -303,23 +297,18 @@ export function SimulationRoot(props: {simulationId: string}) { ) }); - // TODO: use multiple rows return ( - - - - - - - - - - {layoutComponents} - - - - - - + + + + + + + + {layoutComponents} + + + + ) } diff --git a/react/src/data/appwrapper.ts b/react/src/data/appwrapper.ts index fb27d86443..1d1327a597 100644 --- a/react/src/data/appwrapper.ts +++ b/react/src/data/appwrapper.ts @@ -108,7 +108,8 @@ export class AppWrapper { }).then(); } - saveModelsToServer = (simulationInfo: SimulationInfoRaw, models: StoreState): Promise => { + /*saveModelsToServer = (simulationInfo: SimulationInfoRaw, models: StoreState): Promise => { + simulationInfo = {...simulationInfo}; // clone, no mutations simulationInfo.models = models; return fetch("/save-simulation", { method: 'POST', @@ -117,5 +118,5 @@ export class AppWrapper { }, body: JSON.stringify(simulationInfo) }) - } + }*/ } diff --git a/react/src/data/middleware/middleware.ts b/react/src/data/middleware/middleware.ts index b4c60d5eba..afa6699368 100644 --- a/react/src/data/middleware/middleware.ts +++ b/react/src/data/middleware/middleware.ts @@ -1,10 +1,11 @@ import { Middleware } from "redux"; +import { SimulationInfo } from "../../component/simulation"; import { Schema } from "../../utility/schema"; import { saveMiddleware } from "./save"; import { shadowBeamlineSortingMiddleware } from "./shadow/beamline"; import { shadowBeamlineWatchpointReportsMiddleware } from "./shadow/watchpoint"; -export type ConfigurableMiddleware = (config: C, schema: Schema) => Middleware +export type ConfigurableMiddleware = (config: C, schema: Schema, simulationInfo: SimulationInfo) => Middleware export const Middlewares: {[key: string]: ConfigurableMiddleware} = { shadowWatchpointsFromBeamline: shadowBeamlineWatchpointReportsMiddleware, @@ -12,6 +13,6 @@ export const Middlewares: {[key: string]: ConfigurableMiddleware} = { save: saveMiddleware } -export function middlewaresForSchema(schema: Schema): Middleware[] { - return (schema.middleware || []).map(sm => Middlewares[sm.type](sm.config, schema)); +export function middlewaresForSchema(schema: Schema, simulationInfo: SimulationInfo): Middleware[] { + return (schema.middleware || []).map(sm => Middlewares[sm.type](sm.config, schema, simulationInfo)); } diff --git a/react/src/data/middleware/save.ts b/react/src/data/middleware/save.ts index 3a2f452cd7..ff4987876e 100644 --- a/react/src/data/middleware/save.ts +++ b/react/src/data/middleware/save.ts @@ -1,11 +1,11 @@ import { ConfigurableMiddleware } from "./middleware" export type SaveMiddlewareConfig = { - minIntervalSeconds: number, + debounceDelaySeconds: number, maxIntervalSeconds: number } -export const saveMiddleware: ConfigurableMiddleware = (config, schema) => { +export const saveMiddleware: ConfigurableMiddleware = (config, schema, simulationInfo) => { let saveTimeout = undefined; let firstUpdateInSave = undefined; return store => next => action => { @@ -17,7 +17,7 @@ export const saveMiddleware: ConfigurableMiddleware = (con clearTimeout(saveTimeout); } - let timeUntilSave = Math.min(config.minIntervalSeconds, Math.min(0, config.maxIntervalSeconds - (Date.now() - firstUpdateInSave) / 1000)) + let timeUntilSave = Math.min(config.debounceDelaySeconds, Math.min(0, config.maxIntervalSeconds - (Date.now() - firstUpdateInSave) / 1000)) saveTimeout = setTimeout(() => { firstUpdateInSave = undefined; diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index ae9f429cee..4560e066bd 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -61,13 +61,13 @@ export function panelLayout(settings: { let submit = () => { formHandleFactory.save(store.getState(), dispatch); - simulationInfoPromise.then(simulationInfo => { + /*simulationInfoPromise.then(simulationInfo => { appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); - }) + })*/ } - let _cancel = + //let _cancel = let formProps = { submit: submit, diff --git a/sirepo/package_data/static/react-json/common-schema.json b/sirepo/package_data/static/react-json/common-schema.json index 6036be4b78..1385406d3f 100644 --- a/sirepo/package_data/static/react-json/common-schema.json +++ b/sirepo/package_data/static/react-json/common-schema.json @@ -53,6 +53,15 @@ } }, + "middleware": [ + { + "type": "save", + "config": { + "debounceDelaySeconds": 0.5, + "maxIntervalSeconds": 1 + } + } + ], "constants": { "paymentPlans": { "basic": "Sirepo Basic", diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 3be7aa88fd..5858360e7e 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -6483,7 +6483,7 @@ "config": { "tabs": [ { - "name": "lattic", + "name": "lattice", "title": "Lattice", "items": [ { From 792aae5a9404c7280e46c606c741a3220012b9e2 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 2 May 2023 23:15:03 +0000 Subject: [PATCH 40/68] wip fix save function --- react/src/component/simulation.tsx | 6 +++--- react/src/data/appwrapper.ts | 12 ------------ react/src/data/middleware/middleware.ts | 2 +- react/src/data/middleware/save.ts | 20 +++++++++++++++++++- 4 files changed, 23 insertions(+), 17 deletions(-) diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index 0ed733eb00..a9a3b29f89 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -65,8 +65,8 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri simulation_id: simulationId, pretty: "0" })).then(async (resp) => { - let simulationInfo = await resp.json(); - let models = simulationInfo['models'] as ModelState[]; + let simulationInfo = {...(await resp.json() as SimulationInfoRaw), simulationId} as SimulationInfo; + let models = simulationInfo['models'] as StoreState; let _store = configureStore({ reducer: { @@ -85,7 +85,7 @@ function SimulationInfoInitializer(props: { simulationId: string } & {[key: stri })) } - resolve({...simulationInfo, simulationId}); + resolve(simulationInfo); updateHasInit(true); }) })) diff --git a/react/src/data/appwrapper.ts b/react/src/data/appwrapper.ts index 1d1327a597..34f51749c6 100644 --- a/react/src/data/appwrapper.ts +++ b/react/src/data/appwrapper.ts @@ -107,16 +107,4 @@ export class AppWrapper { }) }).then(); } - - /*saveModelsToServer = (simulationInfo: SimulationInfoRaw, models: StoreState): Promise => { - simulationInfo = {...simulationInfo}; // clone, no mutations - simulationInfo.models = models; - return fetch("/save-simulation", { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(simulationInfo) - }) - }*/ } diff --git a/react/src/data/middleware/middleware.ts b/react/src/data/middleware/middleware.ts index afa6699368..89e9892ad2 100644 --- a/react/src/data/middleware/middleware.ts +++ b/react/src/data/middleware/middleware.ts @@ -1,5 +1,5 @@ import { Middleware } from "redux"; -import { SimulationInfo } from "../../component/simulation"; +import { SimulationInfo, SimulationInfoRaw } from "../../component/simulation"; import { Schema } from "../../utility/schema"; import { saveMiddleware } from "./save"; import { shadowBeamlineSortingMiddleware } from "./shadow/beamline"; diff --git a/react/src/data/middleware/save.ts b/react/src/data/middleware/save.ts index ff4987876e..2925bc84ae 100644 --- a/react/src/data/middleware/save.ts +++ b/react/src/data/middleware/save.ts @@ -1,3 +1,7 @@ +import { SimulationInfo } from "../../component/simulation"; +import { StoreState } from "../../store/common"; +import { ModelState } from "../../store/models"; +import { StoreTypes } from "../data"; import { ConfigurableMiddleware } from "./middleware" export type SaveMiddlewareConfig = { @@ -5,6 +9,18 @@ export type SaveMiddlewareConfig = { maxIntervalSeconds: number } +const saveModelsToServer = (simulationInfo: SimulationInfo, models: StoreState): Promise => { + simulationInfo = {...simulationInfo}; // clone, no mutations + simulationInfo.models = models; + return fetch("/save-simulation", { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(simulationInfo) + }) +} + export const saveMiddleware: ConfigurableMiddleware = (config, schema, simulationInfo) => { let saveTimeout = undefined; let firstUpdateInSave = undefined; @@ -21,7 +37,9 @@ export const saveMiddleware: ConfigurableMiddleware = (con saveTimeout = setTimeout(() => { firstUpdateInSave = undefined; - + console.log("simulationInfo", simulationInfo); + console.log("models", store.getState()[StoreTypes.Models.name]) + saveModelsToServer(simulationInfo, store.getState()[StoreTypes.Models.name]) }, timeUntilSave) } return next(action); From 2c92f0e92dece5d69740a6c060fa8078e14cd057 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 3 May 2023 20:41:48 +0000 Subject: [PATCH 41/68] wip create beamline elements component --- react/src/component/reusable/panel.tsx | 24 +- react/src/data/alias.ts | 73 +- react/src/data/form.ts | 33 +- react/src/layout/layouts.ts | 4 +- react/src/layout/madx/beamlineElements.tsx | 203 +- react/src/layout/panel.tsx | 115 +- .../static/react-json/madx-schema.json | 3417 ++++++++--------- 7 files changed, 2035 insertions(+), 1834 deletions(-) diff --git a/react/src/component/reusable/panel.tsx b/react/src/component/reusable/panel.tsx index 528334fce2..14c5f8bfcf 100644 --- a/react/src/component/reusable/panel.tsx +++ b/react/src/component/reusable/panel.tsx @@ -12,7 +12,14 @@ import { v4 as uuidv4 } from 'uuid'; import { CPanelController } from "../../data/panel" import { PanelController } from "../../data/panel"; -export function Panel(props) { +export type PanelProps = { + panelBodyShown: boolean, + title: string, + buttons?: JSX.Element[] | JSX.Element, + children?: React.ReactNode +} + +export function Panel(props: PanelProps) { let { title, buttons, panelBodyShown } = props; let [panelButtonsId] = useState(() => uuidv4()); @@ -47,7 +54,7 @@ export function Panel(props) { ); } -export function ViewPanelActionButtons(props) { +export function ViewPanelActionButtons(props: { onSave: () => void, onCancel: () => void, canSave: boolean }) { let { canSave, onSave, onCancel } = props; return ( @@ -57,7 +64,18 @@ export function ViewPanelActionButtons(props) { ) } -export function EditorPanel(props) { +export type EditorPanelProps = { + submit: () => void, + cancel: () => void, + showButtons: boolean, + mainChildren: JSX.Element[], + modalChildren: JSX.Element[], + formValid: boolean, + title: string, + id: string +} + +export function EditorPanel(props: EditorPanelProps) { let { submit, cancel, diff --git a/react/src/data/alias.ts b/react/src/data/alias.ts index e44ea9f45e..5e6ac095e1 100644 --- a/react/src/data/alias.ts +++ b/react/src/data/alias.ts @@ -1,11 +1,15 @@ import { Dispatch, AnyAction } from "redux"; import { ArrayFieldState, StoreState } from "../store/common"; import { Schema } from "../utility/schema"; -import { getValueSelector, StoreType } from "./data"; +import { expandDataStructure, getValueSelector, revertDataStructure, StoreType, StoreTypes, ValueSelectors } from "./data"; import { Dependency } from "./dependency"; import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; import cloneDeep from 'lodash/cloneDeep'; import { ModelState } from "../store/models"; +import { FormModelState } from "../store/formState"; +import { callNextParentFunction, FormActionFunc, formStateFromSingleValue, initialFormStateFromValue } from "./form"; +import { mapProperties } from "../utility/object"; +import { useState } from "react"; export type ArrayAliases = { realDataLocation: { @@ -58,25 +62,80 @@ export class HandleFactoryWithArrayAliases extends HandleFactory { export type HandleFactoryOverrides = { fake: string, - value: ModelState + value: ModelState, + formValue?: FormModelState, + onSave?: (value: ModelState) => void }[] export class HandleFactoryWithOverrides extends HandleFactory { constructor(schema: Schema, private overrides: HandleFactoryOverrides, parent: HandleFactory) { super(schema, parent); + + overrides.forEach(ov => { + ov.formValue = mapProperties(ov.value, (n, i) => initialFormStateFromValue(i)); + }) + + console.log("overrides", overrides); + } + + save: FormActionFunc = (state: any, dispatch: Dispatch) => { + //callNextParentFunction(this, "save", state, dispatch); + this.overrides.forEach(o => o.onSave && o.onSave(o.value)); + } + + cancel: FormActionFunc = (state: any, dispatch: Dispatch) => { + //callNextParentFunction(this, "cancel", state, dispatch); + + } + + isDirty = (): boolean => { + //debugger; + return this.overrides.flatMap(o => Object.entries(o.formValue).map(([n, v]) => v.touched)).includes(true); + } + + isValid = (state: any): boolean => { + return !(this.overrides.flatMap(o => Object.entries(o.formValue).map(([n, v]) => v.valid)).includes(false)); + } + + updateHooks: {[key: string]: (() => void)[]} = {}; + + addNotify = (dependency: Dependency, func: () => void) => { + let k = dependency.getDependencyString(); + if(!(k in this.updateHooks)) { + this.updateHooks[k] = []; + } + this.updateHooks[k].push(func); + } + + notify = (dependency: Dependency) => { + let k = dependency.getDependencyString(); + (this.updateHooks[k] || []).forEach(f => f()); } createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle> => { let override = this.overrides.find(a => a.fake === dependency.modelName); - + let inst = this; + console.log(`resolving dependency=${dependency.getDependencyString()}`) if(override !== undefined) { + console.log(`overriding handle for dependency=${dependency.getDependencyString()}, override=${JSON.stringify(override)}`); return new (class implements EmptyDataHandle { private createDummyHandle(): DataHandle { - let mv = override.value; + let mv = type === StoreTypes.Models ? override.value : override.formValue; let fv = mv[dependency.fieldName] as F; + console.log(`${dependency.getDependencyString()} = ${JSON.stringify(fv)}`) return new (class extends DataHandle { - write() { - throw new Error("tried to write to read-only handle override"); + write(value: F, state: any, dispatch: Dispatch) { + inst.notify(dependency); + mv[dependency.fieldName] = value; + + if(type === StoreTypes.FormState) { + let type = inst.schema.models[dependency.modelName][dependency.fieldName].type + let rawValue = revertDataStructure(value as any, getValueSelector(StoreTypes.FormState)); + console.log("rawValue", rawValue); + let v = type.toModelValue(rawValue); + console.log("value", v); + override.value[dependency.fieldName] = v; + } } })(fv); } @@ -85,6 +144,8 @@ export class HandleFactoryWithOverrides extends HandleFactory { return this.createDummyHandle(); } hook(): DataHandle { + let [s, us] = useState({}); + inst.addNotify(dependency, () => us({})) return this.createDummyHandle(); } })(); diff --git a/react/src/data/form.ts b/react/src/data/form.ts index 3514544fc9..2332ebb008 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -9,7 +9,7 @@ import { StoreType, StoreTypes, expandDataStructure, revertDataStructure, getVal import { Dependency } from "./dependency"; import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; -type FormActionFunc = (state: any, dispatch: Dispatch) => void +export type FormActionFunc = (state: any, dispatch: Dispatch) => void type FormSelectorFunc = (state: any) => V type FormActions = { @@ -22,7 +22,7 @@ export function formStateFromModelState(modelState: ModelState): FormModelState return mapProperties(modelState, (name, value) => initialFormStateFromValue(value)); } -function formStateFromSingleValue(value: T): FormFieldState { +export function formStateFromSingleValue(value: T): FormFieldState { return { valid: true, value, @@ -34,6 +34,18 @@ export function initialFormStateFromValue(value: T): FormFieldState { return expandDataStructure(value, formStateFromSingleValue); } +export const callNextParentFunction = (inst: HandleFactory, fnName: 'save' | 'cancel', state: any, dispatch: Dispatch) => { + let p = inst.parent; + while(p) { + let fn: FormActionFunc = p[fnName]; + if(fn) { + fn(state, dispatch); + return; + } + p = p.parent; + } +} + export class FormStateHandleFactory extends HandleFactory { private updated: Dictionary = new Dictionary(); private listeners: Dictionary void> = new Dictionary(); @@ -75,29 +87,18 @@ export class FormStateHandleFactory extends HandleFactory { this.listeners.items().forEach(l => l.value()); } - private callParentFunctions = (fnName: 'save' | 'cancel', state: any, dispatch: Dispatch) => { - let p = this.parent; - while(p) { - let fn: FormActionFunc = p[fnName]; - if(fn) { - fn(state, dispatch); - } - p = p.parent; - } - } - save: FormActionFunc = (state: any, dispatch: Dispatch) => { this.updated.items().forEach(u => u.value.save(state, dispatch)); this.updated = new Dictionary(); this.notifyListeners(); - this.callParentFunctions("save", state, dispatch); + callNextParentFunction(this, "save", state, dispatch); } cancel: FormActionFunc = (state: any, dispatch: Dispatch) => { this.updated.items().forEach(u => u.value.cancel(state, dispatch)); this.updated = new Dictionary(); this.notifyListeners(); - this.callParentFunctions("cancel", state, dispatch); + callNextParentFunction(this, "cancel", state, dispatch); } isDirty = (): boolean => { @@ -137,7 +138,7 @@ export class FormStateHandleFactory extends HandleFactory { m(state).write(v, state, dispatch); }, cancel: (state: StoreState, dispatch: Dispatch) => { - //f(state).write(initialFormStateFromValue(m(state).value), state, dispatch); + f(state).write(initialFormStateFromValue(m(state).value), state, dispatch); }, valid: (state: any): boolean => { return f(state).value.valid; diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index c4e5919a24..a9f376efcf 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -19,6 +19,7 @@ import { WaterfallLayout } from "./arrange/waterfall"; import { Histogram2dFromApi } from "./report/histogram2d"; import { ShadowBeamlineWatchpointReports } from "./shadow/beamlineWatchpointReports"; import { ShadowBeamlineLayout } from "./shadow/beamline"; +import { MadxBeamlineElementsLayout } from "./madx/beamlineElements"; // TODO rename to LayoutsWrapper @@ -46,7 +47,8 @@ class LayoutWrapper { vStack: VerticalStackLayout, waterfall: WaterfallLayout, shadowBeamlineWatchpointReports: ShadowBeamlineWatchpointReports, - shadowBeamline: LayoutWithFormController(ShadowBeamlineLayout) + shadowBeamline: LayoutWithFormController(ShadowBeamlineLayout), + madxBeamlineElements: MadxBeamlineElementsLayout } constructor () { diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index b1cb3519e1..1c06aa0814 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -1,14 +1,74 @@ +import React, { useContext, useState } from "react"; +import { FunctionComponent } from "react"; +import { Badge, Button, Modal, Tab, Table, Tabs } from "react-bootstrap"; +import { useDispatch, useStore } from "react-redux"; +import { formActionFunctions } from "../../component/reusable/form"; +import { EditorPanel, Panel, ViewPanelActionButtons } from "../../component/reusable/panel"; +import { HandleFactoryWithOverrides } from "../../data/alias"; +import { CSchema } from "../../data/appwrapper"; +import { getValueSelector, newModelFromSchema, revertDataStructure, StoreTypes } from "../../data/data"; +import { Dependency } from "../../data/dependency"; +import { CHandleFactory, DataHandle } from "../../data/handle"; +import { useCoupledState } from "../../hook/coupling"; +import { ArrayFieldElement, ArrayFieldState } from "../../store/common"; +import { FormFieldState } from "../../store/formState"; +import { ModelState } from "../../store/models"; import { Layout } from "../layout"; +import { LAYOUTS } from "../layouts"; + +type TemplateSettings = { + type: string, + name: string, + modelName: string, + items: SchemaLayoutJson[] +} export type MadxBeamlineElementsConfig = { - beamlinesDependency: string, elementsDependency: string, - elementsTemplates: { - group: string, - type: string, + templateGroups: { name: string, - items: SchemaLayoutJson[] - }[] + types: string[] + }[], + elementTemplates: TemplateSettings[] +} + +function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplete: (modelState: ModelState) => void, name: string, onHide: () => void }) { + let [layouts, _, updated] = useCoupledState(props.template, () => props.template.items.map((i, idx) => { + return LAYOUTS.getLayoutForSchema(i); + })) + + let schema = useContext(CSchema); + let store = useStore(); + let dispatch = useDispatch(); + let parentHandleFactory = useContext(CHandleFactory); + + let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [ + { + fake: props.template.modelName, + value: newModelFromSchema(schema.models[props.template.modelName], { name: props.name }), + onSave: props.onComplete + } + ], parentHandleFactory); + + return ( + + + + {props.template.name} + + + {layouts.map((l, idx) => { + let Comp = l.component; + return ; + })} + + { + overridesHandleFactory.save(store.getState(), dispatch) + props.onHide(); + }} onCancel={props.onHide} canSave={overridesHandleFactory.isValid(store.getState())}/> + + + ) } export class MadxBeamlineElementsLayout extends Layout { @@ -16,5 +76,136 @@ export class MadxBeamlineElementsLayout extends Layout = (props) => { + let handleFactory = useContext(CHandleFactory); + //let activeBeamlineId = handleFactory.createHandle(new Dependency(this.config.activeBeamlineDependency), StoreTypes.Models).hook().value; + let elementsHandle = handleFactory.createHandle(new Dependency(this.config.elementsDependency), StoreTypes.FormState).hook(); + let elementsValue = revertDataStructure(elementsHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; + + let [newElementModalShown, updateNewElementModalShown] = useState(false); + let [shownModalTemplate, updateShownModalTemplate] = useState(undefined); + let defaultGroup = this.config.templateGroups?.length > 0 ? this.config.templateGroups[0].name : undefined; + + let uniqueNameForType = (type: string) => { + let maxId = elementsValue.filter(e => e.model.charAt(0) === type.charAt(0)).reduce((prev: number, cur: ArrayFieldElement, idx) => { + let numberPart = (/.*?(\d*).*?/g).exec(cur.item.name as string)[1]; + return Math.max(prev, parseInt(numberPart.length > 0 ? numberPart : "0")) + }, 1); + return `${type.charAt(0)}${maxId + 1}` + } + let getTemplateSettingsByType = (type: string) => { + let ret = this.config.elementTemplates.find(t => { + return t.type == type + }); + if(!ret) { + throw new Error(`could not find template settings for type=${type}, ${JSON.stringify(this.config.elementTemplates)}`) + } + return ret; + } + + let addBeamlineElement = (template: TemplateSettings, modelValue: ModelState) => { + console.log(`adding beamline element with type=${template.type}`, modelValue); + } + + return ( + <> + updateNewElementModalShown(false)}> + + New Beamline Element + + + + { + this.config.templateGroups?.map(tg => { + return ( + + { + ([...new Set(tg.types)].sort((a,b) => a.localeCompare(b))).map(t => { + let s = getTemplateSettingsByType(t); + return ( + + ) + }) + } + + ) + }) + } + + + + { + shownModalTemplate && ( + updateShownModalTemplate(undefined)} template={shownModalTemplate} onComplete={(mv) => addBeamlineElement(shownModalTemplate, mv)}/> + ) + } + +
+
+ +
+ + + + + + + + + + { + [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { + return ( + + + + + { + elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { + return ( + + + + + + + + + + ) + }) + } + + ) + + }) + } +
NameDescriptionLengthBend
+ + {category} + +
+
+ + {ev.item.name as string} + +
+
+ {/*??? TODO: garsuga: where does description come from*/} + + {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} + + {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} +
+
+
+ + + ) + } } diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index 4560e066bd..acd465c472 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -2,7 +2,7 @@ import { useContext } from "react"; import { interpolate } from "../utility/string"; import { LayoutProps, Layout } from "./layout"; import { useDispatch, useStore } from "react-redux"; -import { EditorPanel } from "../component/reusable/panel"; +import { EditorPanel, EditorPanelProps } from "../component/reusable/panel"; import "./panel.scss"; import React from "react"; import { CAppWrapper, CSimulationInfoPromise } from "../data/appwrapper"; @@ -12,7 +12,6 @@ import { useShown } from "../hook/shown"; import { StoreTypes } from "../data/data"; import { CHandleFactory } from "../data/handle"; import { FormStateHandleFactory } from "../data/form"; -import { modelsSlice } from "../store/models"; import { AnyAction, Dispatch } from "redux"; export type PanelConfig = { @@ -22,74 +21,54 @@ export type PanelConfig = { shown: string } -export type PanelActionFunction = (formHandleFactory: FormStateHandleFactory, state: any, dispatch: Dispatch) => void; -export function panelLayout(settings: { - save?: PanelActionFunction, - cancel?: PanelActionFunction -}) { - return class extends Layout { - basic?: Layout[]; - advanced?: Layout[]; - - constructor(config: PanelConfig) { - super(config); - this.basic = (!!config.basic) ? config.basic.map(LAYOUTS.getLayoutForSchema) : undefined; - this.advanced = (!!config.advanced) ? config.advanced.map(LAYOUTS.getLayoutForSchema) : undefined; - } - - component = (props: LayoutProps<{}>) => { - let simulationInfoPromise = useContext(CSimulationInfoPromise); - let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; - formHandleFactory.useUpdates(PanelLayout); - let appWrapper = useContext(CAppWrapper); - - let shown = useShown(this.config.shown, true, StoreTypes.Models); - - let store = useStore(); - let dispatch = useDispatch(); - - let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); - - let mapLayoutsToComponents = (views: Layout[]) => views.map((child, idx) => { - let LayoutComponent = child.component; - return ; - }); - - let mainChildren = (!!this.basic) ? mapLayoutsToComponents(this.basic) : undefined; - let modalChildren = (!!this.advanced) ? mapLayoutsToComponents(this.advanced) : undefined; - - let submit = () => { - formHandleFactory.save(store.getState(), dispatch); - /*simulationInfoPromise.then(simulationInfo => { - appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); - })*/ - - } +export class PanelLayout extends Layout { + basic?: Layout[]; + advanced?: Layout[]; + + constructor(config: PanelConfig) { + super(config); + this.basic = (!!config.basic) ? config.basic.map(LAYOUTS.getLayoutForSchema) : undefined; + this.advanced = (!!config.advanced) ? config.advanced.map(LAYOUTS.getLayoutForSchema) : undefined; + } + + component = (props: LayoutProps<{}>) => { + let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + formHandleFactory.useUpdates(PanelLayout); + + let shown = useShown(this.config.shown, true, StoreTypes.Models); + + let store = useStore(); + let dispatch = useDispatch(); - //let _cancel = - - let formProps = { - submit: submit, - cancel: () => formHandleFactory.cancel(store.getState(), dispatch), - showButtons: formHandleFactory.isDirty(), - formValid: formHandleFactory.isValid(store.getState()), - mainChildren, - modalChildren, - title: title || this.name, - id: this.name - } - - return ( - <> - { - shown && - } - - - ) + let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); + + let mapLayoutsToComponents = (views: Layout[]) => views.map((child, idx) => { + let LayoutComponent = child.component; + return ; + }); + + let mainChildren = (!!this.basic) ? mapLayoutsToComponents(this.basic) : undefined; + let modalChildren = (!!this.advanced) ? mapLayoutsToComponents(this.advanced) : undefined; + + let formProps: EditorPanelProps = { + submit: (() => formHandleFactory.save(store.getState(), dispatch)), + cancel: (() => formHandleFactory.cancel(store.getState(), dispatch)), + showButtons: formHandleFactory.isDirty(), + formValid: formHandleFactory.isValid(store.getState()), + mainChildren, + modalChildren, + title: title || this.name, + id: this.name } + + return ( + <> + { + shown && + } + + + ) } } - -export const PanelLayout = panelLayout({}); diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 5858360e7e..402f342637 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -6485,30 +6485,6 @@ { "name": "lattice", "title": "Lattice", - "items": [ - { - "layout": "waterfall", - "config": { - "breakpoints": { - "sm": 1, - "md": 2, - "xl": 3 - }, - "gutters": { - "horizontal": ".5em", - "vertical": ".5em" - }, - "padding": ".5em", - "items": [ - - ] - } - } - ] - }, - { - "name": "source", - "title": "Source", "items": [ { "layout": "waterfall", @@ -6525,1645 +6501,1607 @@ "padding": ".5em", "items": [ { - "layout": "panel", + "layout": "madxBeamlineElements", "config": { - "basic": [ + "elementsDependency": "elements.elements", + "templateGroups": [ { - "layout": "tabs", - "config": { - "tabs": [ - { - "name": "Main", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "command_beam.particle", - "command_beam.mass", - "command_beam.charge", - "bunch.beamDefinition", - "command_beam.energy", - "command_beam.pc", - "command_beam.gamma", - "command_beam.beta", - "command_beam.brho" - ] - } - } - ] - }, - { - "name": "Distribution", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "bunch.matchTwissParameters", - "simulation.visualizationBeamlineId" - ] - } - }, - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "EX [m]", - "description": "The horizontal emittance.", - "fields": [ - "command_beam.ex", - "command_beam.ey" - ] - }, - { - "label": "Horizontal Beta [m]", - "fields": [ - "bunch.betx", - "bunch.bety" - ] - }, - { - "label": "Horizontal Alpha", - "fields": [ - "bunch.alfx", - "bunch.alfy" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "command_beam.et", - "command_beam.sigt", - "command_beam.sige" - ] - } - } - ] - }, - { - "name": "Position", - "items": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Centroid [m]", - "fields": [ - "bunch.x", - "bunch.y" - ] - }, - { - "label": "Horizontal Canonical Momentum of $p_x$", - "fields": [ - "bunch.px", - "bunch.py" - ] - } - ] - } - } - ] - }, - { - "name": "Particle Count", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "bunch.numberOfParticles", - "bunch.randomSeed" - ] - } - } - ] - } - ] - } + "name": "Basic", + "types": ["SBEND", "RBEND", "DRIFT", "COLLIMATOR", "ECOLLIMATOR", "RCOLLIMATOR", "KICKER", "MARKER", "QUADRUPOLE", "SEXTUPOLE"] + }, + { + "name": "Advanced", + "types": ["BEAMBEAM", "CHANGEREF", "CRABCAVITY", "DIPEDGE", "HACDIPOLE", "HKICKER", "HMONITOR", "INSTRUMENT", "MATRIX", "MONITOR", "MULTIPOLE", "NLLENS", "OCTUPOLE", "PLACEHOLDER", "RFCAVITY", "RFMULTIPOLE", "SOLENOID", "SROTATION", "TRANSLATION", "TWCAVITY", "VACDIPOLE", "VKICKER", "VMONITOR", "XROTATION", "YROTATION"] + }, + { + "name": "All Elements", + "types": ["SBEND", "RBEND", "DRIFT", "COLLIMATOR", "ECOLLIMATOR", "RCOLLIMATOR", "KICKER", "MARKER", "QUADRUPOLE", "SEXTUPOLE", "BEAMBEAM", "CHANGEREF", "CRABCAVITY", "DIPEDGE", "HACDIPOLE", "HKICKER", "HMONITOR", "INSTRUMENT", "MATRIX", "MONITOR", "MULTIPOLE", "NLLENS", "OCTUPOLE", "PLACEHOLDER", "RFCAVITY", "RFMULTIPOLE", "SOLENOID", "SROTATION", "TRANSLATION", "TWCAVITY", "VACDIPOLE", "VKICKER", "VMONITOR", "XROTATION", "YROTATION"] } ], - "advanced": [], - "title": "Bunch" - }, - "_NAME": "bunch" - }, - { - "layout": "panel", - "config": { - "basic": [ + "elementTemplates": [ { - "layout": "autoRunReport", - "config": { - "report": "bunchReport1", - "dependencies": [ - "lattice.*", - "elements.*", - "bunch.*" - ], - "reportLayout": { - "layout": "heatplot", + "type": "BEAMBEAM", + "name": "BEAMBEAM", + "modelName": "BEAMBEAM", + "items": [ + { + "layout": "fieldList", "config": { + "fields": [ + "BEAMBEAM.name", + "BEAMBEAM.sigx", + "BEAMBEAM.sigy", + "BEAMBEAM.xma", + "BEAMBEAM.yma", + "BEAMBEAM.charge", + "BEAMBEAM.bbshape", + "BEAMBEAM.width", + "BEAMBEAM.bbdir", + "BEAMBEAM.apertype", + "BEAMBEAM.aperture", + "BEAMBEAM.aper_offset", + "BEAMBEAM.aper_tol" + ] } } - } - } - ], - "advanced": [ + ] + }, { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Phase Space Coordinate", + "type": "CHANGEREF", + "name": "CHANGEREF", + "modelName": "CHANGEREF", + "items": [ + { + "layout": "fieldList", + "config": { "fields": [ - "bunchReport1.x", - "bunchReport1.y" + "CHANGEREF.name", + "CHANGEREF.patch_ang", + "CHANGEREF.patch_trans", + "CHANGEREF.apertype", + "CHANGEREF.aperture", + "CHANGEREF.aper_offset", + "CHANGEREF.aper_tol" ] } - ] - } + } + ] }, { - "layout": "fieldList", - "config": { - "fields": [ - "bunchReport1.histogramBins", - "bunchReport1.colorMap", - "bunchReport1.notes" - ] - } - } - ], - "title": "Bunch Report" - }, - "_NAME": "bunchReport1" - }, - { - "layout": "panel", - "config": { - "basic": [ - { - "layout": "autoRunReport", - "config": { - "report": "bunchReport2", - "dependencies": [ - "lattice.*", - "elements.*", - "bunch.*" - ], - "reportLayout": { - "layout": "heatplot", + "type": "COLLIMATOR", + "name": "COLLIMATOR", + "modelName": "COLLIMATOR", + "items": [ + { + "layout": "fieldList", "config": { + "fields": [ + "COLLIMATOR.name", + "COLLIMATOR.l", + "COLLIMATOR.apertype", + "COLLIMATOR.aperture", + "COLLIMATOR.aper_offset", + "COLLIMATOR.aper_tol" + ] } } - } - } - ], - "advanced": [ + ] + }, { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Phase Space Coordinate", + "type": "CRABCAVITY", + "name": "CRABCAVITY", + "modelName": "CRABCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { "fields": [ - "bunchReport2.x", - "bunchReport2.y" + "CRABCAVITY.name", + "CRABCAVITY.l", + "CRABCAVITY.volt", + "CRABCAVITY.lag", + "CRABCAVITY.freq", + "CRABCAVITY.rv1", + "CRABCAVITY.rv2", + "CRABCAVITY.rv3", + "CRABCAVITY.rv4", + "CRABCAVITY.rph1", + "CRABCAVITY.rph2", + "CRABCAVITY.lagf", + "CRABCAVITY.apertype", + "CRABCAVITY.aperture", + "CRABCAVITY.aper_offset", + "CRABCAVITY.aper_tol" ] } - ] - } + } + ] }, { - "layout": "fieldList", - "config": { - "fields": [ - "bunchReport2.histogramBins", - "bunchReport2.colorMap", - "bunchReport2.notes" - ] - } - } - ], - "title": "Bunch Report" - }, - "_NAME": "bunchReport2" - }, - { - "layout": "panel", - "config": { - "basic": [ + "type": "DIPEDGE", + "name": "DIPEDGE", + "modelName": "DIPEDGE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DIPEDGE.name", + "DIPEDGE.h", + "DIPEDGE.e1", + "DIPEDGE.fint", + "DIPEDGE.hgap", + "DIPEDGE.tilt", + "DIPEDGE.apertype", + "DIPEDGE.aperture", + "DIPEDGE.aper_offset", + "DIPEDGE.aper_tol" + ] + } + } + ] + }, { - "layout": "autoRunReport", - "config": { - "report": "bunchReport3", - "dependencies": [ - "lattice.*", - "elements.*", - "bunch.*" - ], - "reportLayout": { - "layout": "heatplot", + "type": "DRIFT", + "name": "DRIFT", + "modelName": "DRIFT", + "items": [ + { + "layout": "fieldList", "config": { + "fields": [ + "DRIFT.name", + "DRIFT.l" + ] } } - } - } - ], - "advanced": [ + ] + }, { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Phase Space Coordinate", + "type": "ECOLLIMATOR", + "name": "ECOLLIMATOR", + "modelName": "ECOLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { "fields": [ - "bunchReport3.x", - "bunchReport3.y" + "ECOLLIMATOR.name", + "ECOLLIMATOR.l", + "ECOLLIMATOR.xsize", + "ECOLLIMATOR.ysize", + "ECOLLIMATOR.apertype", + "ECOLLIMATOR.aperture", + "ECOLLIMATOR.aper_offset", + "ECOLLIMATOR.aper_tol" ] } - ] - } + } + ] }, { - "layout": "fieldList", - "config": { - "fields": [ - "bunchReport3.histogramBins", - "bunchReport3.colorMap", - "bunchReport3.notes" - ] - } - } - ], - "title": "Bunch Report" - }, - "_NAME": "bunchReport3" - }, - { - "layout": "panel", - "config": { - "basic": [ + "type": "HACDIPOLE", + "name": "HACDIPOLE", + "modelName": "HACDIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HACDIPOLE.name", + "HACDIPOLE.l", + "HACDIPOLE.volt", + "HACDIPOLE.freq", + "HACDIPOLE.lag", + "HACDIPOLE.ramp1", + "HACDIPOLE.ramp2", + "HACDIPOLE.ramp3", + "HACDIPOLE.ramp4", + "HACDIPOLE.apertype", + "HACDIPOLE.aperture", + "HACDIPOLE.aper_offset", + "HACDIPOLE.aper_tol" + ] + } + } + ] + }, { - "layout": "autoRunReport", - "config": { - "report": "bunchReport4", - "dependencies": [ - "lattice.*", - "elements.*", - "bunch.*" - ], - "reportLayout": { - "layout": "heatplot", + "type": "HKICKER", + "name": "HKICKER", + "modelName": "HKICKER", + "items": [ + { + "layout": "fieldList", "config": { + "fields": [ + "HKICKER.name", + "HKICKER.l", + "HKICKER.kick", + "HKICKER.tilt", + "HKICKER.apertype", + "HKICKER.aperture", + "HKICKER.aper_offset", + "HKICKER.aper_tol" + ] } } - } - } - ], - "advanced": [ + ] + }, { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Phase Space Coordinate", + "type": "HMONITOR", + "name": "HMONITOR", + "modelName": "HMONITOR", + "items": [ + { + "layout": "fieldList", + "config": { "fields": [ - "bunchReport4.x", - "bunchReport4.y" + "HMONITOR.name", + "HMONITOR.l", + "HMONITOR.apertype", + "HMONITOR.aperture", + "HMONITOR.aper_offset", + "HMONITOR.aper_tol" ] } - ] - } + } + ] }, { - "layout": "fieldList", - "config": { - "fields": [ - "bunchReport4.histogramBins", - "bunchReport4.colorMap", - "bunchReport4.notes" - ] - } - } - ], - "title": "Bunch Report" - }, - "_NAME": "bunchReport4" - } - ] - } - } - ] - }, - { - "name": "visualization", - "title": "Visualization", - "items": [ - { - "layout": "waterfall", - "config": { - "breakpoints": { - "sm": 1, - "md": 2, - "xl": 3 - }, - "gutters": { - "horizontal": ".5em", - "vertical": ".5em" - }, - "padding": ".5em", - "items": [ - { - "layout": "panel", - "config": { - "basic": [ + "type": "INSTRUMENT", + "name": "INSTRUMENT", + "modelName": "INSTRUMENT", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "INSTRUMENT.name", + "INSTRUMENT.l", + "INSTRUMENT.apertype", + "INSTRUMENT.aperture", + "INSTRUMENT.aper_offset", + "INSTRUMENT.aper_tol" + ] + } + } + ] + }, { - "layout": "fieldList", - "config": { - "fields": [ - "simulation.visualizationBeamlineId", - "bunch.numberOfParticles", - "simulation.computeTwissFromParticles" - ] - } - } - ], - "advanced": [], - "title": "Simulation Settings" - }, - "_NAME": "simulationSettings" - }, - { - "layout": "panel", - "config": { - "advanced": [ + "type": "KICKER", + "name": "KICKER", + "modelName": "KICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "KICKER.name", + "KICKER.l", + "KICKER.hkick", + "KICKER.vkick", + "KICKER.tilt", + "KICKER.apertype", + "KICKER.aperture", + "KICKER.aper_offset", + "KICKER.aper_tol" + ] + } + } + ] + }, { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.x" - ] - } - } - ] - } - }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.y1", - "twissFromParticlesAnimation.y2", - "twissFromParticlesAnimation.y3" - ] - } - } - ] - } + "type": "MARKER", + "name": "MARKER", + "modelName": "MARKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MARKER.name", + "MARKER.apertype", + "MARKER.aperture", + "MARKER.aper_offset", + "MARKER.aper_tol" + ] } - ] - } + } + ] }, { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.includeLattice", - "twissFromParticlesAnimation.notes" - ] - } - } - ], - "title": "Twiss From Particles" - }, - "_NAME": "twissFromParticlesAnimation" + "type": "MATRIX", + "name": "MATRIX", + "modelName": "MATRIX", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MATRIX.name", + "MATRIX.l", + "MATRIX.kick1", + "MATRIX.kick6", + "MATRIX.rm11", + "MATRIX.rm66", + "MATRIX.tm111", + "MATRIX.tm666", + "MATRIX.kick2", + "MATRIX.kick3", + "MATRIX.kick4", + "MATRIX.kick5", + "MATRIX.rm12", + "MATRIX.rm13", + "MATRIX.rm14", + "MATRIX.rm15", + "MATRIX.rm16", + "MATRIX.rm21", + "MATRIX.rm22", + "MATRIX.rm23", + "MATRIX.rm24", + "MATRIX.rm25", + "MATRIX.rm26", + "MATRIX.rm31", + "MATRIX.rm32", + "MATRIX.rm33", + "MATRIX.rm34", + "MATRIX.rm35", + "MATRIX.rm36", + "MATRIX.rm41", + "MATRIX.rm42", + "MATRIX.rm43", + "MATRIX.rm44", + "MATRIX.rm45", + "MATRIX.rm46", + "MATRIX.rm51", + "MATRIX.rm52", + "MATRIX.rm53", + "MATRIX.rm54", + "MATRIX.rm55", + "MATRIX.rm56", + "MATRIX.rm61", + "MATRIX.rm62", + "MATRIX.rm63", + "MATRIX.rm64", + "MATRIX.rm65", + "MATRIX.tm112", + "MATRIX.tm113", + "MATRIX.tm114", + "MATRIX.tm115", + "MATRIX.tm116", + "MATRIX.tm121", + "MATRIX.tm122", + "MATRIX.tm123", + "MATRIX.tm124", + "MATRIX.tm125", + "MATRIX.tm126", + "MATRIX.tm131", + "MATRIX.tm132", + "MATRIX.tm133", + "MATRIX.tm134", + "MATRIX.tm135", + "MATRIX.tm136", + "MATRIX.tm141", + "MATRIX.tm142", + "MATRIX.tm143", + "MATRIX.tm144", + "MATRIX.tm145", + "MATRIX.tm146", + "MATRIX.tm151", + "MATRIX.tm152", + "MATRIX.tm153", + "MATRIX.tm154", + "MATRIX.tm155", + "MATRIX.tm156", + "MATRIX.tm161", + "MATRIX.tm162", + "MATRIX.tm163", + "MATRIX.tm164", + "MATRIX.tm165", + "MATRIX.tm166", + "MATRIX.tm211", + "MATRIX.tm212", + "MATRIX.tm213", + "MATRIX.tm214", + "MATRIX.tm215", + "MATRIX.tm216", + "MATRIX.tm221", + "MATRIX.tm222", + "MATRIX.tm223", + "MATRIX.tm224", + "MATRIX.tm225", + "MATRIX.tm226", + "MATRIX.tm231", + "MATRIX.tm232", + "MATRIX.tm233", + "MATRIX.tm234", + "MATRIX.tm235", + "MATRIX.tm236", + "MATRIX.tm241", + "MATRIX.tm242", + "MATRIX.tm243", + "MATRIX.tm244", + "MATRIX.tm245", + "MATRIX.tm246", + "MATRIX.tm251", + "MATRIX.tm252", + "MATRIX.tm253", + "MATRIX.tm254", + "MATRIX.tm255", + "MATRIX.tm256", + "MATRIX.tm261", + "MATRIX.tm262", + "MATRIX.tm263", + "MATRIX.tm264", + "MATRIX.tm265", + "MATRIX.tm266", + "MATRIX.tm311", + "MATRIX.tm312", + "MATRIX.tm313", + "MATRIX.tm314", + "MATRIX.tm315", + "MATRIX.tm316", + "MATRIX.tm321", + "MATRIX.tm322", + "MATRIX.tm323", + "MATRIX.tm324", + "MATRIX.tm325", + "MATRIX.tm326", + "MATRIX.tm331", + "MATRIX.tm332", + "MATRIX.tm333", + "MATRIX.tm334", + "MATRIX.tm335", + "MATRIX.tm336", + "MATRIX.tm341", + "MATRIX.tm342", + "MATRIX.tm343", + "MATRIX.tm344", + "MATRIX.tm345", + "MATRIX.tm346", + "MATRIX.tm351", + "MATRIX.tm352", + "MATRIX.tm353", + "MATRIX.tm354", + "MATRIX.tm355", + "MATRIX.tm356", + "MATRIX.tm361", + "MATRIX.tm362", + "MATRIX.tm363", + "MATRIX.tm364", + "MATRIX.tm365", + "MATRIX.tm366", + "MATRIX.tm411", + "MATRIX.tm412", + "MATRIX.tm413", + "MATRIX.tm414", + "MATRIX.tm415", + "MATRIX.tm416", + "MATRIX.tm421", + "MATRIX.tm422", + "MATRIX.tm423", + "MATRIX.tm424", + "MATRIX.tm425", + "MATRIX.tm426", + "MATRIX.tm431", + "MATRIX.tm432", + "MATRIX.tm433", + "MATRIX.tm434", + "MATRIX.tm435", + "MATRIX.tm436", + "MATRIX.tm441", + "MATRIX.tm442", + "MATRIX.tm443", + "MATRIX.tm444", + "MATRIX.tm445", + "MATRIX.tm446", + "MATRIX.tm451", + "MATRIX.tm452", + "MATRIX.tm453", + "MATRIX.tm454", + "MATRIX.tm455", + "MATRIX.tm456", + "MATRIX.tm461", + "MATRIX.tm462", + "MATRIX.tm463", + "MATRIX.tm464", + "MATRIX.tm465", + "MATRIX.tm466", + "MATRIX.tm511", + "MATRIX.tm512", + "MATRIX.tm513", + "MATRIX.tm514", + "MATRIX.tm515", + "MATRIX.tm516", + "MATRIX.tm521", + "MATRIX.tm522", + "MATRIX.tm523", + "MATRIX.tm524", + "MATRIX.tm525", + "MATRIX.tm526", + "MATRIX.tm531", + "MATRIX.tm532", + "MATRIX.tm533", + "MATRIX.tm534", + "MATRIX.tm535", + "MATRIX.tm536", + "MATRIX.tm541", + "MATRIX.tm542", + "MATRIX.tm543", + "MATRIX.tm544", + "MATRIX.tm545", + "MATRIX.tm546", + "MATRIX.tm551", + "MATRIX.tm552", + "MATRIX.tm553", + "MATRIX.tm554", + "MATRIX.tm555", + "MATRIX.tm556", + "MATRIX.tm561", + "MATRIX.tm562", + "MATRIX.tm563", + "MATRIX.tm564", + "MATRIX.tm565", + "MATRIX.tm566", + "MATRIX.tm611", + "MATRIX.tm612", + "MATRIX.tm613", + "MATRIX.tm614", + "MATRIX.tm615", + "MATRIX.tm616", + "MATRIX.tm621", + "MATRIX.tm622", + "MATRIX.tm623", + "MATRIX.tm624", + "MATRIX.tm625", + "MATRIX.tm626", + "MATRIX.tm631", + "MATRIX.tm632", + "MATRIX.tm633", + "MATRIX.tm634", + "MATRIX.tm635", + "MATRIX.tm636", + "MATRIX.tm641", + "MATRIX.tm642", + "MATRIX.tm643", + "MATRIX.tm644", + "MATRIX.tm645", + "MATRIX.tm646", + "MATRIX.tm651", + "MATRIX.tm652", + "MATRIX.tm653", + "MATRIX.tm654", + "MATRIX.tm655", + "MATRIX.tm656", + "MATRIX.tm661", + "MATRIX.tm662", + "MATRIX.tm663", + "MATRIX.tm664", + "MATRIX.tm665" + ] + } + } + ] + }, + { + "type": "MONITOR", + "name": "MONITOR", + "modelName": "MONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MONITOR.name", + "MONITOR.l", + "MONITOR.apertype", + "MONITOR.aperture", + "MONITOR.aper_offset", + "MONITOR.aper_tol" + ] + } + } + ] + }, + { + "type": "MULTIPOLE", + "name": "MULTIPOLE", + "modelName": "MULTIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MULTIPOLE.name", + "MULTIPOLE.lrad", + "MULTIPOLE.tilt", + "MULTIPOLE.knl", + "MULTIPOLE.ksl", + "MULTIPOLE.apertype", + "MULTIPOLE.aperture", + "MULTIPOLE.aper_offset", + "MULTIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "NLLENS", + "name": "NLLENS", + "modelName": "NLLENS", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "NLLENS.name", + "NLLENS.knll", + "NLLENS.cnll", + "NLLENS.apertype", + "NLLENS.aperture", + "NLLENS.aper_offset", + "NLLENS.aper_tol" + ] + } + } + ] + }, + { + "type": "OCTUPOLE", + "name": "OCTUPOLE", + "modelName": "OCTUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "OCTUPOLE.name", + "OCTUPOLE.l", + "OCTUPOLE.k3", + "OCTUPOLE.k3s", + "OCTUPOLE.tilt", + "OCTUPOLE.apertype", + "OCTUPOLE.aperture", + "OCTUPOLE.aper_offset", + "OCTUPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "PLACEHOLDER", + "name": "PLACEHOLDER", + "modelName": "PLACEHOLDER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "PLACEHOLDER.name", + "PLACEHOLDER.l", + "PLACEHOLDER.apertype", + "PLACEHOLDER.aperture", + "PLACEHOLDER.aper_offset", + "PLACEHOLDER.aper_tol" + ] + } + } + ] + }, + { + "type": "QUADRUPOLE", + "name": "QUADRUPOLE", + "modelName": "QUADRUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "QUADRUPOLE.name", + "QUADRUPOLE.l", + "QUADRUPOLE.k1", + "QUADRUPOLE.k1s", + "QUADRUPOLE.tilt", + "QUADRUPOLE.thick", + "QUADRUPOLE.apertype", + "QUADRUPOLE.aperture", + "QUADRUPOLE.aper_offset", + "QUADRUPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "RBEND", + "name": "RBEND", + "modelName": "RBEND", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RBEND.name", + "RBEND.l", + "RBEND.angle", + "RBEND.tilt", + "RBEND.k1", + "RBEND.k2", + "RBEND.e1", + "RBEND.e2", + "RBEND.fint", + "RBEND.fintx", + "RBEND.hgap", + "RBEND.h1", + "RBEND.h2", + "RBEND.add_angle", + "RBEND.thick", + "RBEND.apertype", + "RBEND.aperture", + "RBEND.aper_offset", + "RBEND.aper_tol" + ] + } + } + ] + }, + { + "type": "RCOLLIMATOR", + "name": "RCOLLIMATOR", + "modelName": "RCOLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RCOLLIMATOR.name", + "RCOLLIMATOR.l", + "RCOLLIMATOR.xsize", + "RCOLLIMATOR.ysize", + "RCOLLIMATOR.apertype", + "RCOLLIMATOR.aperture", + "RCOLLIMATOR.aper_offset", + "RCOLLIMATOR.aper_tol" + ] + } + } + ] + }, + { + "type": "RFCAVITY", + "name": "RFCAVITY", + "modelName": "RFCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFCAVITY.name", + "RFCAVITY.l", + "RFCAVITY.volt", + "RFCAVITY.lag", + "RFCAVITY.harmon", + "RFCAVITY.freq", + "RFCAVITY.apertype", + "RFCAVITY.aperture", + "RFCAVITY.aper_offset", + "RFCAVITY.aper_tol" + ] + } + } + ] + }, + { + "type": "RFMULTIPOLE", + "name": "RFMULTIPOLE", + "modelName": "RFMULTIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFMULTIPOLE.name", + "RFMULTIPOLE.volt", + "RFMULTIPOLE.lag", + "RFMULTIPOLE.harmon", + "RFMULTIPOLE.freq", + "RFMULTIPOLE.lrad", + "RFMULTIPOLE.tilt", + "RFMULTIPOLE.knl", + "RFMULTIPOLE.ksl", + "RFMULTIPOLE.pnl", + "RFMULTIPOLE.psl", + "RFMULTIPOLE.apertype", + "RFMULTIPOLE.aperture", + "RFMULTIPOLE.aper_offset", + "RFMULTIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "SBEND", + "name": "SBEND", + "modelName": "SBEND", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SBEND.name", + "SBEND.l", + "SBEND.angle", + "SBEND.k1", + "SBEND.k2", + "SBEND.e1", + "SBEND.e2", + "SBEND.tilt", + "SBEND.h1", + "SBEND.h2", + "SBEND.hgap", + "SBEND.fint", + "SBEND.fintx", + "SBEND.thick", + "SBEND.apertype", + "SBEND.aperture", + "SBEND.aper_offset", + "SBEND.aper_tol" + ] + } + } + ] + }, + { + "type": "SEXTUPOLE", + "name": "SEXTUPOLE", + "modelName": "SEXTUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SEXTUPOLE.name", + "SEXTUPOLE.l", + "SEXTUPOLE.k2", + "SEXTUPOLE.k2s", + "SEXTUPOLE.tilt", + "SEXTUPOLE.apertype", + "SEXTUPOLE.aperture", + "SEXTUPOLE.aper_offset", + "SEXTUPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "SOLENOID", + "name": "SOLENOID", + "modelName": "SOLENOID", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SOLENOID.name", + "SOLENOID.l", + "SOLENOID.ks", + "SOLENOID.ksi", + "SOLENOID.apertype", + "SOLENOID.aperture", + "SOLENOID.aper_offset", + "SOLENOID.aper_tol" + ] + } + } + ] + }, + { + "type": "SROTATION", + "name": "SROTATION", + "modelName": "SROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SROTATION.name", + "SROTATION.angle", + "SROTATION.apertype", + "SROTATION.aperture", + "SROTATION.aper_offset", + "SROTATION.aper_tol" + ] + } + } + ] + }, + { + "type": "TRANSLATION", + "name": "TRANSLATION", + "modelName": "TRANSLATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TRANSLATION.name", + "TRANSLATION.dx", + "TRANSLATION.dy", + "TRANSLATION.ds" + ] + } + } + ] + }, + { + "type": "TWCAVITY", + "name": "TWCAVITY", + "modelName": "TWCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TWCAVITY.name", + "TWCAVITY.l", + "TWCAVITY.volt", + "TWCAVITY.freq", + "TWCAVITY.lag", + "TWCAVITY.psi", + "TWCAVITY.delta_lag", + "TWCAVITY.apertype", + "TWCAVITY.aperture", + "TWCAVITY.aper_offset", + "TWCAVITY.aper_tol" + ] + } + } + ] + }, + { + "type": "VACDIPOLE", + "name": "VACDIPOLE", + "modelName": "VACDIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VACDIPOLE.name", + "VACDIPOLE.l", + "VACDIPOLE.volt", + "VACDIPOLE.freq", + "VACDIPOLE.lag", + "VACDIPOLE.ramp1", + "VACDIPOLE.ramp2", + "VACDIPOLE.ramp3", + "VACDIPOLE.ramp4", + "VACDIPOLE.apertype", + "VACDIPOLE.aperture", + "VACDIPOLE.aper_offset", + "VACDIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "VKICKER", + "name": "VKICKER", + "modelName": "VKICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VKICKER.name", + "VKICKER.l", + "VKICKER.kick", + "VKICKER.tilt", + "VKICKER.apertype", + "VKICKER.aperture", + "VKICKER.aper_offset", + "VKICKER.aper_tol" + ] + } + } + ] + }, + { + "type": "VMONITOR", + "name": "VMONITOR", + "modelName": "VMONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VMONITOR.name", + "VMONITOR.l", + "VMONITOR.apertype", + "VMONITOR.aperture", + "VMONITOR.aper_offset", + "VMONITOR.aper_tol" + ] + } + } + ] + }, + { + "type": "XROTATION", + "name": "XROTATION", + "modelName": "XROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "XROTATION.name", + "XROTATION.angle", + "XROTATION.apertype", + "XROTATION.aperture", + "XROTATION.aper_offset", + "XROTATION.aper_tol" + ] + } + } + ] + }, + { + "type": "YROTATION", + "name": "YROTATION", + "modelName": "YROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "YROTATION.name", + "YROTATION.angle", + "YROTATION.apertype", + "YROTATION.aperture", + "YROTATION.aper_offset", + "YROTATION.aper_tol" + ] + } + } + ] + } + ] + } } ] } } ] - } - - ] - } - } - ], - "unusedViews": [ - { - "layout": "panel", - "config": { - "advanced": [ + }, { - "layout": "fieldList", - "config": { - "fields": [ - "beamline.name" - ] - } - } - ], - "title": "Beamline" - }, - "_NAME": "beamline" - }, - [ - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "beamlineReport.notes" - ] - } - } - ], - "title": "Lattice" - }, - "_NAME": "beamlineReport" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldTable", - "config": { - "columns": [ - "Horizontal", - "Vertical" - ], - "rows": [ - { - "label": "Horizontal Value to Plot", - "fields": [ - "elementAnimation.x", - "elementAnimation.y1" - ] - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.framesPerSecond", - "elementAnimation.histogramBins", - "elementAnimation.aspectRatio", - "elementAnimation.colorMap", - "elementAnimation.notes" - ] - } - } - ], - "title": "Output Report" - }, - "_NAME": "heatmapFrameAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.x" - ] - } - } - ] - } + "name": "source", + "title": "Source", + "items": [ + { + "layout": "waterfall", + "config": { + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "padding": ".5em", + "items": [ + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "tabs", + "config": { + "tabs": [ + { + "name": "Main", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.particle", + "command_beam.mass", + "command_beam.charge", + "bunch.beamDefinition", + "command_beam.energy", + "command_beam.pc", + "command_beam.gamma", + "command_beam.beta", + "command_beam.brho" + ] + } + } + ] + }, + { + "name": "Distribution", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bunch.matchTwissParameters", + "simulation.visualizationBeamlineId" + ] + } + }, + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "EX [m]", + "description": "The horizontal emittance.", + "fields": [ + "command_beam.ex", + "command_beam.ey" + ] + }, + { + "label": "Horizontal Beta [m]", + "fields": [ + "bunch.betx", + "bunch.bety" + ] + }, + { + "label": "Horizontal Alpha", + "fields": [ + "bunch.alfx", + "bunch.alfy" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "command_beam.et", + "command_beam.sigt", + "command_beam.sige" + ] + } + } + ] + }, + { + "name": "Position", + "items": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Centroid [m]", + "fields": [ + "bunch.x", + "bunch.y" + ] + }, + { + "label": "Horizontal Canonical Momentum of $p_x$", + "fields": [ + "bunch.px", + "bunch.py" + ] + } + ] + } + } + ] + }, + { + "name": "Particle Count", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "bunch.numberOfParticles", + "bunch.randomSeed" + ] + } + } + ] + } + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.y1", - "elementAnimation.y2", - "elementAnimation.y3" - ] + ], + "advanced": [], + "title": "Bunch" + }, + "_NAME": "bunch" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport1", + "dependencies": [ + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } } - } - ] - } - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.framesPerSecond", - "elementAnimation.includeLattice", - "elementAnimation.notes" - ] - } - } - ], - "title": "Output Report" - }, - "_NAME": "plotFrameAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [], - "title": "Match Summary" - }, - "_NAME": "matchSummaryAnimation" - }, - - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "twissEllipseReport.dim" - ] - } - } - ], - "title": "Twiss Ellipse" - }, - "_NAME": "twissEllipseReport" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "hStack", - "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport1.x", + "bunchReport1.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport1.histogramBins", + "bunchReport1.colorMap", + "bunchReport1.notes" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.x" - ] + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport1" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport2", + "dependencies": [ + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } } - } - ] - } - }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport2.x", + "bunchReport2.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport2.histogramBins", + "bunchReport2.colorMap", + "bunchReport2.notes" + ] + } } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.y1", - "elementAnimation.y2", - "elementAnimation.y3" - ] + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport2" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport3", + "dependencies": [ + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } } - } - ] - } - } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "elementAnimation.includeLattice" - ] - } - } - ], - "title": "Twiss Parameters" - }, - "_NAME": "twissAnimation" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "twissReport.y1", - "twissReport.y2", - "twissReport.y3", - "twissReport.includeLattice" - ] - } - } - ], - "title": "Twiss Parameters" - }, - "_NAME": "twissReport" - } - ], - [ - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "BEAMBEAM.name", - "BEAMBEAM.sigx", - "BEAMBEAM.sigy", - "BEAMBEAM.xma", - "BEAMBEAM.yma", - "BEAMBEAM.charge", - "BEAMBEAM.bbshape", - "BEAMBEAM.width", - "BEAMBEAM.bbdir", - "BEAMBEAM.apertype", - "BEAMBEAM.aperture", - "BEAMBEAM.aper_offset", - "BEAMBEAM.aper_tol" - ] - } - } - ], - "title": "BEAMBEAM" - }, - "_NAME": "BEAMBEAM" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "CHANGEREF.name", - "CHANGEREF.patch_ang", - "CHANGEREF.patch_trans", - "CHANGEREF.apertype", - "CHANGEREF.aperture", - "CHANGEREF.aper_offset", - "CHANGEREF.aper_tol" - ] - } - } - ], - "title": "CHANGEREF" - }, - "_NAME": "CHANGEREF" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "COLLIMATOR.name", - "COLLIMATOR.l", - "COLLIMATOR.apertype", - "COLLIMATOR.aperture", - "COLLIMATOR.aper_offset", - "COLLIMATOR.aper_tol" - ] - } - } - ], - "title": "COLLIMATOR" - }, - "_NAME": "COLLIMATOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "CRABCAVITY.name", - "CRABCAVITY.l", - "CRABCAVITY.volt", - "CRABCAVITY.lag", - "CRABCAVITY.freq", - "CRABCAVITY.rv1", - "CRABCAVITY.rv2", - "CRABCAVITY.rv3", - "CRABCAVITY.rv4", - "CRABCAVITY.rph1", - "CRABCAVITY.rph2", - "CRABCAVITY.lagf", - "CRABCAVITY.apertype", - "CRABCAVITY.aperture", - "CRABCAVITY.aper_offset", - "CRABCAVITY.aper_tol" - ] - } - } - ], - "title": "CRABCAVITY" - }, - "_NAME": "CRABCAVITY" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "DIPEDGE.name", - "DIPEDGE.h", - "DIPEDGE.e1", - "DIPEDGE.fint", - "DIPEDGE.hgap", - "DIPEDGE.tilt", - "DIPEDGE.apertype", - "DIPEDGE.aperture", - "DIPEDGE.aper_offset", - "DIPEDGE.aper_tol" - ] - } - } - ], - "title": "DIPEDGE" - }, - "_NAME": "DIPEDGE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "DRIFT.name", - "DRIFT.l" - ] - } - } - ], - "title": "DRIFT" - }, - "_NAME": "DRIFT" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "ECOLLIMATOR.name", - "ECOLLIMATOR.l", - "ECOLLIMATOR.xsize", - "ECOLLIMATOR.ysize", - "ECOLLIMATOR.apertype", - "ECOLLIMATOR.aperture", - "ECOLLIMATOR.aper_offset", - "ECOLLIMATOR.aper_tol" - ] - } - } - ], - "title": "ECOLLIMATOR" - }, - "_NAME": "ECOLLIMATOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HACDIPOLE.name", - "HACDIPOLE.l", - "HACDIPOLE.volt", - "HACDIPOLE.freq", - "HACDIPOLE.lag", - "HACDIPOLE.ramp1", - "HACDIPOLE.ramp2", - "HACDIPOLE.ramp3", - "HACDIPOLE.ramp4", - "HACDIPOLE.apertype", - "HACDIPOLE.aperture", - "HACDIPOLE.aper_offset", - "HACDIPOLE.aper_tol" - ] - } - } - ], - "title": "HACDIPOLE" - }, - "_NAME": "HACDIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HKICKER.name", - "HKICKER.l", - "HKICKER.kick", - "HKICKER.tilt", - "HKICKER.apertype", - "HKICKER.aperture", - "HKICKER.aper_offset", - "HKICKER.aper_tol" - ] - } - } - ], - "title": "HKICKER" - }, - "_NAME": "HKICKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HMONITOR.name", - "HMONITOR.l", - "HMONITOR.apertype", - "HMONITOR.aperture", - "HMONITOR.aper_offset", - "HMONITOR.aper_tol" - ] - } - } - ], - "title": "HMONITOR" - }, - "_NAME": "HMONITOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "INSTRUMENT.name", - "INSTRUMENT.l", - "INSTRUMENT.apertype", - "INSTRUMENT.aperture", - "INSTRUMENT.aper_offset", - "INSTRUMENT.aper_tol" - ] - } - } - ], - "title": "INSTRUMENT" - }, - "_NAME": "INSTRUMENT" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "KICKER.name", - "KICKER.l", - "KICKER.hkick", - "KICKER.vkick", - "KICKER.tilt", - "KICKER.apertype", - "KICKER.aperture", - "KICKER.aper_offset", - "KICKER.aper_tol" - ] - } - } - ], - "title": "KICKER" - }, - "_NAME": "KICKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MARKER.name", - "MARKER.apertype", - "MARKER.aperture", - "MARKER.aper_offset", - "MARKER.aper_tol" - ] - } - } - ], - "title": "MARKER" - }, - "_NAME": "MARKER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MATRIX.name", - "MATRIX.l", - "MATRIX.kick1", - "MATRIX.kick6", - "MATRIX.rm11", - "MATRIX.rm66", - "MATRIX.tm111", - "MATRIX.tm666", - "MATRIX.kick2", - "MATRIX.kick3", - "MATRIX.kick4", - "MATRIX.kick5", - "MATRIX.rm12", - "MATRIX.rm13", - "MATRIX.rm14", - "MATRIX.rm15", - "MATRIX.rm16", - "MATRIX.rm21", - "MATRIX.rm22", - "MATRIX.rm23", - "MATRIX.rm24", - "MATRIX.rm25", - "MATRIX.rm26", - "MATRIX.rm31", - "MATRIX.rm32", - "MATRIX.rm33", - "MATRIX.rm34", - "MATRIX.rm35", - "MATRIX.rm36", - "MATRIX.rm41", - "MATRIX.rm42", - "MATRIX.rm43", - "MATRIX.rm44", - "MATRIX.rm45", - "MATRIX.rm46", - "MATRIX.rm51", - "MATRIX.rm52", - "MATRIX.rm53", - "MATRIX.rm54", - "MATRIX.rm55", - "MATRIX.rm56", - "MATRIX.rm61", - "MATRIX.rm62", - "MATRIX.rm63", - "MATRIX.rm64", - "MATRIX.rm65", - "MATRIX.tm112", - "MATRIX.tm113", - "MATRIX.tm114", - "MATRIX.tm115", - "MATRIX.tm116", - "MATRIX.tm121", - "MATRIX.tm122", - "MATRIX.tm123", - "MATRIX.tm124", - "MATRIX.tm125", - "MATRIX.tm126", - "MATRIX.tm131", - "MATRIX.tm132", - "MATRIX.tm133", - "MATRIX.tm134", - "MATRIX.tm135", - "MATRIX.tm136", - "MATRIX.tm141", - "MATRIX.tm142", - "MATRIX.tm143", - "MATRIX.tm144", - "MATRIX.tm145", - "MATRIX.tm146", - "MATRIX.tm151", - "MATRIX.tm152", - "MATRIX.tm153", - "MATRIX.tm154", - "MATRIX.tm155", - "MATRIX.tm156", - "MATRIX.tm161", - "MATRIX.tm162", - "MATRIX.tm163", - "MATRIX.tm164", - "MATRIX.tm165", - "MATRIX.tm166", - "MATRIX.tm211", - "MATRIX.tm212", - "MATRIX.tm213", - "MATRIX.tm214", - "MATRIX.tm215", - "MATRIX.tm216", - "MATRIX.tm221", - "MATRIX.tm222", - "MATRIX.tm223", - "MATRIX.tm224", - "MATRIX.tm225", - "MATRIX.tm226", - "MATRIX.tm231", - "MATRIX.tm232", - "MATRIX.tm233", - "MATRIX.tm234", - "MATRIX.tm235", - "MATRIX.tm236", - "MATRIX.tm241", - "MATRIX.tm242", - "MATRIX.tm243", - "MATRIX.tm244", - "MATRIX.tm245", - "MATRIX.tm246", - "MATRIX.tm251", - "MATRIX.tm252", - "MATRIX.tm253", - "MATRIX.tm254", - "MATRIX.tm255", - "MATRIX.tm256", - "MATRIX.tm261", - "MATRIX.tm262", - "MATRIX.tm263", - "MATRIX.tm264", - "MATRIX.tm265", - "MATRIX.tm266", - "MATRIX.tm311", - "MATRIX.tm312", - "MATRIX.tm313", - "MATRIX.tm314", - "MATRIX.tm315", - "MATRIX.tm316", - "MATRIX.tm321", - "MATRIX.tm322", - "MATRIX.tm323", - "MATRIX.tm324", - "MATRIX.tm325", - "MATRIX.tm326", - "MATRIX.tm331", - "MATRIX.tm332", - "MATRIX.tm333", - "MATRIX.tm334", - "MATRIX.tm335", - "MATRIX.tm336", - "MATRIX.tm341", - "MATRIX.tm342", - "MATRIX.tm343", - "MATRIX.tm344", - "MATRIX.tm345", - "MATRIX.tm346", - "MATRIX.tm351", - "MATRIX.tm352", - "MATRIX.tm353", - "MATRIX.tm354", - "MATRIX.tm355", - "MATRIX.tm356", - "MATRIX.tm361", - "MATRIX.tm362", - "MATRIX.tm363", - "MATRIX.tm364", - "MATRIX.tm365", - "MATRIX.tm366", - "MATRIX.tm411", - "MATRIX.tm412", - "MATRIX.tm413", - "MATRIX.tm414", - "MATRIX.tm415", - "MATRIX.tm416", - "MATRIX.tm421", - "MATRIX.tm422", - "MATRIX.tm423", - "MATRIX.tm424", - "MATRIX.tm425", - "MATRIX.tm426", - "MATRIX.tm431", - "MATRIX.tm432", - "MATRIX.tm433", - "MATRIX.tm434", - "MATRIX.tm435", - "MATRIX.tm436", - "MATRIX.tm441", - "MATRIX.tm442", - "MATRIX.tm443", - "MATRIX.tm444", - "MATRIX.tm445", - "MATRIX.tm446", - "MATRIX.tm451", - "MATRIX.tm452", - "MATRIX.tm453", - "MATRIX.tm454", - "MATRIX.tm455", - "MATRIX.tm456", - "MATRIX.tm461", - "MATRIX.tm462", - "MATRIX.tm463", - "MATRIX.tm464", - "MATRIX.tm465", - "MATRIX.tm466", - "MATRIX.tm511", - "MATRIX.tm512", - "MATRIX.tm513", - "MATRIX.tm514", - "MATRIX.tm515", - "MATRIX.tm516", - "MATRIX.tm521", - "MATRIX.tm522", - "MATRIX.tm523", - "MATRIX.tm524", - "MATRIX.tm525", - "MATRIX.tm526", - "MATRIX.tm531", - "MATRIX.tm532", - "MATRIX.tm533", - "MATRIX.tm534", - "MATRIX.tm535", - "MATRIX.tm536", - "MATRIX.tm541", - "MATRIX.tm542", - "MATRIX.tm543", - "MATRIX.tm544", - "MATRIX.tm545", - "MATRIX.tm546", - "MATRIX.tm551", - "MATRIX.tm552", - "MATRIX.tm553", - "MATRIX.tm554", - "MATRIX.tm555", - "MATRIX.tm556", - "MATRIX.tm561", - "MATRIX.tm562", - "MATRIX.tm563", - "MATRIX.tm564", - "MATRIX.tm565", - "MATRIX.tm566", - "MATRIX.tm611", - "MATRIX.tm612", - "MATRIX.tm613", - "MATRIX.tm614", - "MATRIX.tm615", - "MATRIX.tm616", - "MATRIX.tm621", - "MATRIX.tm622", - "MATRIX.tm623", - "MATRIX.tm624", - "MATRIX.tm625", - "MATRIX.tm626", - "MATRIX.tm631", - "MATRIX.tm632", - "MATRIX.tm633", - "MATRIX.tm634", - "MATRIX.tm635", - "MATRIX.tm636", - "MATRIX.tm641", - "MATRIX.tm642", - "MATRIX.tm643", - "MATRIX.tm644", - "MATRIX.tm645", - "MATRIX.tm646", - "MATRIX.tm651", - "MATRIX.tm652", - "MATRIX.tm653", - "MATRIX.tm654", - "MATRIX.tm655", - "MATRIX.tm656", - "MATRIX.tm661", - "MATRIX.tm662", - "MATRIX.tm663", - "MATRIX.tm664", - "MATRIX.tm665" - ] - } - } - ], - "title": "MATRIX" - }, - "_NAME": "MATRIX" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MONITOR.name", - "MONITOR.l", - "MONITOR.apertype", - "MONITOR.aperture", - "MONITOR.aper_offset", - "MONITOR.aper_tol" - ] - } - } - ], - "title": "MONITOR" - }, - "_NAME": "MONITOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MULTIPOLE.name", - "MULTIPOLE.lrad", - "MULTIPOLE.tilt", - "MULTIPOLE.knl", - "MULTIPOLE.ksl", - "MULTIPOLE.apertype", - "MULTIPOLE.aperture", - "MULTIPOLE.aper_offset", - "MULTIPOLE.aper_tol" - ] - } - } - ], - "title": "MULTIPOLE" - }, - "_NAME": "MULTIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "NLLENS.name", - "NLLENS.knll", - "NLLENS.cnll", - "NLLENS.apertype", - "NLLENS.aperture", - "NLLENS.aper_offset", - "NLLENS.aper_tol" - ] - } - } - ], - "title": "NLLENS" - }, - "_NAME": "NLLENS" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "OCTUPOLE.name", - "OCTUPOLE.l", - "OCTUPOLE.k3", - "OCTUPOLE.k3s", - "OCTUPOLE.tilt", - "OCTUPOLE.apertype", - "OCTUPOLE.aperture", - "OCTUPOLE.aper_offset", - "OCTUPOLE.aper_tol" - ] - } - } - ], - "title": "OCTUPOLE" - }, - "_NAME": "OCTUPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "PLACEHOLDER.name", - "PLACEHOLDER.l", - "PLACEHOLDER.apertype", - "PLACEHOLDER.aperture", - "PLACEHOLDER.aper_offset", - "PLACEHOLDER.aper_tol" - ] - } - } - ], - "title": "PLACEHOLDER" - }, - "_NAME": "PLACEHOLDER" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "QUADRUPOLE.name", - "QUADRUPOLE.l", - "QUADRUPOLE.k1", - "QUADRUPOLE.k1s", - "QUADRUPOLE.tilt", - "QUADRUPOLE.thick", - "QUADRUPOLE.apertype", - "QUADRUPOLE.aperture", - "QUADRUPOLE.aper_offset", - "QUADRUPOLE.aper_tol" - ] - } - } - ], - "title": "QUADRUPOLE" - }, - "_NAME": "QUADRUPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RBEND.name", - "RBEND.l", - "RBEND.angle", - "RBEND.tilt", - "RBEND.k1", - "RBEND.k2", - "RBEND.e1", - "RBEND.e2", - "RBEND.fint", - "RBEND.fintx", - "RBEND.hgap", - "RBEND.h1", - "RBEND.h2", - "RBEND.add_angle", - "RBEND.thick", - "RBEND.apertype", - "RBEND.aperture", - "RBEND.aper_offset", - "RBEND.aper_tol" - ] - } - } - ], - "title": "RBEND" - }, - "_NAME": "RBEND" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RCOLLIMATOR.name", - "RCOLLIMATOR.l", - "RCOLLIMATOR.xsize", - "RCOLLIMATOR.ysize", - "RCOLLIMATOR.apertype", - "RCOLLIMATOR.aperture", - "RCOLLIMATOR.aper_offset", - "RCOLLIMATOR.aper_tol" - ] - } - } - ], - "title": "RCOLLIMATOR" - }, - "_NAME": "RCOLLIMATOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RFCAVITY.name", - "RFCAVITY.l", - "RFCAVITY.volt", - "RFCAVITY.lag", - "RFCAVITY.harmon", - "RFCAVITY.freq", - "RFCAVITY.apertype", - "RFCAVITY.aperture", - "RFCAVITY.aper_offset", - "RFCAVITY.aper_tol" - ] - } - } - ], - "title": "RFCAVITY" - }, - "_NAME": "RFCAVITY" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RFMULTIPOLE.name", - "RFMULTIPOLE.volt", - "RFMULTIPOLE.lag", - "RFMULTIPOLE.harmon", - "RFMULTIPOLE.freq", - "RFMULTIPOLE.lrad", - "RFMULTIPOLE.tilt", - "RFMULTIPOLE.knl", - "RFMULTIPOLE.ksl", - "RFMULTIPOLE.pnl", - "RFMULTIPOLE.psl", - "RFMULTIPOLE.apertype", - "RFMULTIPOLE.aperture", - "RFMULTIPOLE.aper_offset", - "RFMULTIPOLE.aper_tol" - ] + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport3.x", + "bunchReport3.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport3.histogramBins", + "bunchReport3.colorMap", + "bunchReport3.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport3" + }, + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "autoRunReport", + "config": { + "report": "bunchReport4", + "dependencies": [ + "lattice.*", + "elements.*", + "bunch.*" + ], + "reportLayout": { + "layout": "heatplot", + "config": { + } + } + } + } + ], + "advanced": [ + { + "layout": "fieldTable", + "config": { + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Phase Space Coordinate", + "fields": [ + "bunchReport4.x", + "bunchReport4.y" + ] + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "bunchReport4.histogramBins", + "bunchReport4.colorMap", + "bunchReport4.notes" + ] + } + } + ], + "title": "Bunch Report" + }, + "_NAME": "bunchReport4" + } + ] + } } - } - ], - "title": "RFMULTIPOLE" - }, - "_NAME": "RFMULTIPOLE" - }, - { - "layout": "panel", - "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SBEND.name", - "SBEND.l", - "SBEND.angle", - "SBEND.k1", - "SBEND.k2", - "SBEND.e1", - "SBEND.e2", - "SBEND.tilt", - "SBEND.h1", - "SBEND.h2", - "SBEND.hgap", - "SBEND.fint", - "SBEND.fintx", - "SBEND.thick", - "SBEND.apertype", - "SBEND.aperture", - "SBEND.aper_offset", - "SBEND.aper_tol" - ] + ] + }, + { + "name": "visualization", + "title": "Visualization", + "items": [ + { + "layout": "waterfall", + "config": { + "breakpoints": { + "sm": 1, + "md": 2, + "xl": 3 + }, + "gutters": { + "horizontal": ".5em", + "vertical": ".5em" + }, + "padding": ".5em", + "items": [ + { + "layout": "panel", + "config": { + "basic": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "simulation.visualizationBeamlineId", + "bunch.numberOfParticles", + "simulation.computeTwissFromParticles" + ] + } + } + ], + "advanced": [], + "title": "Simulation Settings" + }, + "_NAME": "simulationSettings" + }, + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.y1", + "twissFromParticlesAnimation.y2", + "twissFromParticlesAnimation.y3" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "twissFromParticlesAnimation.includeLattice", + "twissFromParticlesAnimation.notes" + ] + } + } + ], + "title": "Twiss From Particles" + }, + "_NAME": "twissFromParticlesAnimation" + } + ] + } } + ] + } + + ] + } + } + ], + "unusedViews": [ + { + "layout": "panel", + "config": { + "advanced": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "beamline.name" + ] } - ], - "title": "SBEND" - }, - "_NAME": "SBEND" + } + ], + "title": "Beamline" }, + "_NAME": "beamline" + }, + [ { "layout": "panel", "config": { @@ -8172,145 +8110,137 @@ "layout": "fieldList", "config": { "fields": [ - "SEXTUPOLE.name", - "SEXTUPOLE.l", - "SEXTUPOLE.k2", - "SEXTUPOLE.k2s", - "SEXTUPOLE.tilt", - "SEXTUPOLE.apertype", - "SEXTUPOLE.aperture", - "SEXTUPOLE.aper_offset", - "SEXTUPOLE.aper_tol" + "beamlineReport.notes" ] } } ], - "title": "SEXTUPOLE" + "title": "Lattice" }, - "_NAME": "SEXTUPOLE" + "_NAME": "beamlineReport" }, { "layout": "panel", "config": { "advanced": [ { - "layout": "fieldList", + "layout": "fieldTable", "config": { - "fields": [ - "SOLENOID.name", - "SOLENOID.l", - "SOLENOID.ks", - "SOLENOID.ksi", - "SOLENOID.apertype", - "SOLENOID.aperture", - "SOLENOID.aper_offset", - "SOLENOID.aper_tol" + "columns": [ + "Horizontal", + "Vertical" + ], + "rows": [ + { + "label": "Horizontal Value to Plot", + "fields": [ + "elementAnimation.x", + "elementAnimation.y1" + ] + } ] } - } - ], - "title": "SOLENOID" - }, - "_NAME": "SOLENOID" - }, - { - "layout": "panel", - "config": { - "advanced": [ + }, { "layout": "fieldList", "config": { "fields": [ - "SROTATION.name", - "SROTATION.angle", - "SROTATION.apertype", - "SROTATION.aperture", - "SROTATION.aper_offset", - "SROTATION.aper_tol" + "elementAnimation.framesPerSecond", + "elementAnimation.histogramBins", + "elementAnimation.aspectRatio", + "elementAnimation.colorMap", + "elementAnimation.notes" ] } } ], - "title": "SROTATION" + "title": "Output Report" }, - "_NAME": "SROTATION" + "_NAME": "heatmapFrameAnimation" }, { "layout": "panel", "config": { "advanced": [ { - "layout": "fieldList", + "layout": "hStack", "config": { - "fields": [ - "TRANSLATION.name", - "TRANSLATION.dx", - "TRANSLATION.dy", - "TRANSLATION.ds" + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } + } + ] + } + } ] } - } - ], - "title": "TRANSLATION" - }, - "_NAME": "TRANSLATION" - }, - { - "layout": "panel", - "config": { - "advanced": [ + }, { "layout": "fieldList", "config": { "fields": [ - "TWCAVITY.name", - "TWCAVITY.l", - "TWCAVITY.volt", - "TWCAVITY.freq", - "TWCAVITY.lag", - "TWCAVITY.psi", - "TWCAVITY.delta_lag", - "TWCAVITY.apertype", - "TWCAVITY.aperture", - "TWCAVITY.aper_offset", - "TWCAVITY.aper_tol" + "elementAnimation.framesPerSecond", + "elementAnimation.includeLattice", + "elementAnimation.notes" ] } } ], - "title": "TWCAVITY" + "title": "Output Report" }, - "_NAME": "TWCAVITY" + "_NAME": "plotFrameAnimation" }, { "layout": "panel", "config": { - "advanced": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VACDIPOLE.name", - "VACDIPOLE.l", - "VACDIPOLE.volt", - "VACDIPOLE.freq", - "VACDIPOLE.lag", - "VACDIPOLE.ramp1", - "VACDIPOLE.ramp2", - "VACDIPOLE.ramp3", - "VACDIPOLE.ramp4", - "VACDIPOLE.apertype", - "VACDIPOLE.aperture", - "VACDIPOLE.aper_offset", - "VACDIPOLE.aper_tol" - ] - } - } - ], - "title": "VACDIPOLE" + "advanced": [], + "title": "Match Summary" }, - "_NAME": "VACDIPOLE" + "_NAME": "matchSummaryAnimation" }, + { "layout": "panel", "config": { @@ -8319,65 +8249,86 @@ "layout": "fieldList", "config": { "fields": [ - "VKICKER.name", - "VKICKER.l", - "VKICKER.kick", - "VKICKER.tilt", - "VKICKER.apertype", - "VKICKER.aperture", - "VKICKER.aper_offset", - "VKICKER.aper_tol" + "twissEllipseReport.dim" ] } } ], - "title": "VKICKER" + "title": "Twiss Ellipse" }, - "_NAME": "VKICKER" + "_NAME": "twissEllipseReport" }, { "layout": "panel", "config": { "advanced": [ { - "layout": "fieldList", + "layout": "hStack", "config": { - "fields": [ - "VMONITOR.name", - "VMONITOR.l", - "VMONITOR.apertype", - "VMONITOR.aperture", - "VMONITOR.aper_offset", - "VMONITOR.aper_tol" + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } + } + ] + } + } ] } - } - ], - "title": "VMONITOR" - }, - "_NAME": "VMONITOR" - }, - { - "layout": "panel", - "config": { - "advanced": [ + }, { "layout": "fieldList", "config": { "fields": [ - "XROTATION.name", - "XROTATION.angle", - "XROTATION.apertype", - "XROTATION.aperture", - "XROTATION.aper_offset", - "XROTATION.aper_tol" + "elementAnimation.includeLattice" ] } } ], - "title": "XROTATION" + "title": "Twiss Parameters" }, - "_NAME": "XROTATION" + "_NAME": "twissAnimation" }, { "layout": "panel", @@ -8387,19 +8338,17 @@ "layout": "fieldList", "config": { "fields": [ - "YROTATION.name", - "YROTATION.angle", - "YROTATION.apertype", - "YROTATION.aperture", - "YROTATION.aper_offset", - "YROTATION.aper_tol" + "twissReport.y1", + "twissReport.y2", + "twissReport.y3", + "twissReport.includeLattice" ] } } ], - "title": "YROTATION" + "title": "Twiss Parameters" }, - "_NAME": "YROTATION" + "_NAME": "twissReport" } ], [ From ba9c36f57f322278aa039f89fcb3a0196d8f1f27 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 4 May 2023 20:11:15 +0000 Subject: [PATCH 42/68] finish beamline elements component and add beamliens picker component --- react/src/component/reusable/form.tsx | 9 +- react/src/data/middleware/save.ts | 2 +- react/src/layout/layouts.ts | 4 +- react/src/layout/madx/beamlineElements.tsx | 166 +- react/src/layout/madx/beamlinesPicker.tsx | 91 + react/src/layout/navbar.tsx | 4 - react/src/layout/shadow/beamline.tsx | 9 - .../static/react-json/madx-schema.json | 2090 +++++++++-------- 8 files changed, 1254 insertions(+), 1121 deletions(-) create mode 100644 react/src/layout/madx/beamlinesPicker.tsx diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index c5179bb6bb..98725da936 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -48,25 +48,18 @@ export function EditorForm(props) { export function formActionFunctions(config: { formHandleFactory: FormStateHandleFactory, - store: Store, - simulationInfoPromise: Promise, - appWrapper: AppWrapper, + store: Store, dispatch: Dispatch }): { cancel: () => void, submit: () => void } { let { formHandleFactory, store, - simulationInfoPromise, - appWrapper, dispatch } = config; return { cancel: () => formHandleFactory.cancel(store.getState(), dispatch), submit: () => { formHandleFactory.save(store.getState(), dispatch); - /*simulationInfoPromise.then(simulationInfo => { - appWrapper.saveModelsToServer(simulationInfo, store.getState()[modelsSlice.name]); - })*/ } } } diff --git a/react/src/data/middleware/save.ts b/react/src/data/middleware/save.ts index 2925bc84ae..b82d435a88 100644 --- a/react/src/data/middleware/save.ts +++ b/react/src/data/middleware/save.ts @@ -33,7 +33,7 @@ export const saveMiddleware: ConfigurableMiddleware = (con clearTimeout(saveTimeout); } - let timeUntilSave = Math.min(config.debounceDelaySeconds, Math.min(0, config.maxIntervalSeconds - (Date.now() - firstUpdateInSave) / 1000)) + let timeUntilSave = Math.min(config.debounceDelaySeconds, Math.min(0, config.maxIntervalSeconds - ((Date.now() - firstUpdateInSave) / 1000))) saveTimeout = setTimeout(() => { firstUpdateInSave = undefined; diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index a9f376efcf..8b9a34f414 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -20,6 +20,7 @@ import { Histogram2dFromApi } from "./report/histogram2d"; import { ShadowBeamlineWatchpointReports } from "./shadow/beamlineWatchpointReports"; import { ShadowBeamlineLayout } from "./shadow/beamline"; import { MadxBeamlineElementsLayout } from "./madx/beamlineElements"; +import { MadxBeamlinesPickerLayout } from "./madx/beamlinesPicker"; // TODO rename to LayoutsWrapper @@ -48,7 +49,8 @@ class LayoutWrapper { waterfall: WaterfallLayout, shadowBeamlineWatchpointReports: ShadowBeamlineWatchpointReports, shadowBeamline: LayoutWithFormController(ShadowBeamlineLayout), - madxBeamlineElements: MadxBeamlineElementsLayout + madxBeamlineElements: LayoutWithFormController(MadxBeamlineElementsLayout), + madxBeamlinesPicker: MadxBeamlinesPickerLayout } constructor () { diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index 1c06aa0814..649aabde53 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -3,15 +3,15 @@ import { FunctionComponent } from "react"; import { Badge, Button, Modal, Tab, Table, Tabs } from "react-bootstrap"; import { useDispatch, useStore } from "react-redux"; import { formActionFunctions } from "../../component/reusable/form"; -import { EditorPanel, Panel, ViewPanelActionButtons } from "../../component/reusable/panel"; +import { Panel, ViewPanelActionButtons } from "../../component/reusable/panel"; import { HandleFactoryWithOverrides } from "../../data/alias"; import { CSchema } from "../../data/appwrapper"; import { getValueSelector, newModelFromSchema, revertDataStructure, StoreTypes } from "../../data/data"; import { Dependency } from "../../data/dependency"; -import { CHandleFactory, DataHandle } from "../../data/handle"; +import { formStateFromModelState, FormStateHandleFactory } from "../../data/form"; +import { CHandleFactory } from "../../data/handle"; import { useCoupledState } from "../../hook/coupling"; import { ArrayFieldElement, ArrayFieldState } from "../../store/common"; -import { FormFieldState } from "../../store/formState"; import { ModelState } from "../../store/models"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; @@ -32,7 +32,7 @@ export type MadxBeamlineElementsConfig = { elementTemplates: TemplateSettings[] } -function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplete: (modelState: ModelState) => void, name: string, onHide: () => void }) { +function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplete: (modelState: ModelState, model: string) => void, name: string, onHide: () => void }) { let [layouts, _, updated] = useCoupledState(props.template, () => props.template.items.map((i, idx) => { return LAYOUTS.getLayoutForSchema(i); })) @@ -46,7 +46,7 @@ function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplet { fake: props.template.modelName, value: newModelFromSchema(schema.models[props.template.modelName], { name: props.name }), - onSave: props.onComplete + onSave: (v) => props.onComplete(v, props.template.modelName) } ], parentHandleFactory); @@ -77,7 +77,10 @@ export class MadxBeamlineElementsLayout extends Layout = (props) => { - let handleFactory = useContext(CHandleFactory); + let handleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + handleFactory.useUpdates(MadxBeamlineElementsLayout); + let store = useStore(); + let dispatch = useDispatch(); //let activeBeamlineId = handleFactory.createHandle(new Dependency(this.config.activeBeamlineDependency), StoreTypes.Models).hook().value; let elementsHandle = handleFactory.createHandle(new Dependency(this.config.elementsDependency), StoreTypes.FormState).hook(); let elementsValue = revertDataStructure(elementsHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; @@ -104,10 +107,33 @@ export class MadxBeamlineElementsLayout extends Layout { + let addBeamlineElement = (template: TemplateSettings, modelValue: ModelState, model: string) => { console.log(`adding beamline element with type=${template.type}`, modelValue); + + let nv = [...(elementsHandle.value.value as any[])]; + let v = { + item: formStateFromModelState(modelValue), + model: model + } + console.log("nv before", nv); + console.log("V", v); + + nv.push(v) + + elementsHandle.write({ + ...elementsHandle.value, + value: nv + }, store.getState(), dispatch); } + let { cancel, submit } = formActionFunctions({ + formHandleFactory: handleFactory, + store, + dispatch + }); + + let actionButtons = handleFactory.isDirty() ? : undefined; + return ( <> updateNewElementModalShown(false)}> @@ -141,69 +167,75 @@ export class MadxBeamlineElementsLayout extends Layout { shownModalTemplate && ( - updateShownModalTemplate(undefined)} template={shownModalTemplate} onComplete={(mv) => addBeamlineElement(shownModalTemplate, mv)}/> + { + updateShownModalTemplate(undefined); + updateNewElementModalShown(false); + }} template={shownModalTemplate} onComplete={(mv, m) => addBeamlineElement(shownModalTemplate, mv, m)}/> ) } - -
-
- -
- - - - - - - - - - { - [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { - return ( - - - - - { - elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { - return ( - - - - - - - - - - ) - }) - } - - ) - - }) - } -
NameDescriptionLengthBend
- - {category} - -
-
- - {ev.item.name as string} - -
-
- {/*??? TODO: garsuga: where does description come from*/} - - {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} - - {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} -
+
+ {actionButtons} +
+
- + + + + + + + + + + { + [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { + return ( + + + + + { + elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { + if(category === "COLLIMATOR") { + console.log(`${category}`, ev.item); + } + return ( + + + + + + + + + + ) + }) + } + + ) + + }) + } +
NameDescriptionLengthBend
+ + {category} + +
+
+ + {ev.item.name as string} + +
+
+ {/*??? TODO: garsuga: where does description come from*/} + + {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} + + {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} +
+ {actionButtons} +
) diff --git a/react/src/layout/madx/beamlinesPicker.tsx b/react/src/layout/madx/beamlinesPicker.tsx new file mode 100644 index 0000000000..804ec71f74 --- /dev/null +++ b/react/src/layout/madx/beamlinesPicker.tsx @@ -0,0 +1,91 @@ +import React, { useState } from "react" +import { FunctionComponent, useContext } from "react" +import { Button, Table } from "react-bootstrap" +import { useDispatch, useStore } from "react-redux" +import { StoreTypes } from "../../data/data" +import { Dependency } from "../../data/dependency" +import { CHandleFactory } from "../../data/handle" +import { ArrayFieldState } from "../../store/common" +import { ModelState } from "../../store/models" +import { Layout } from "../layout" + +export type MadxBeamlinesPickerConfig = { + selectedBeamlineDependency: string + beamlinesDependency: string +} + +export class MadxBeamlinesPickerLayout extends Layout { + component: FunctionComponent<{ [key: string]: any }> = (props) => { + let handleFactory = useContext(CHandleFactory); + let store = useStore(); + let dispatch = useDispatch(); + let selectedBeamlineIdHandle = handleFactory.createHandle(new Dependency(this.config.selectedBeamlineDependency), StoreTypes.Models).hook(); + let selectedBeamline: number = selectedBeamlineIdHandle.value as number; + let beamlinesHandle = handleFactory.createHandle(new Dependency(this.config.beamlinesDependency), StoreTypes.Models).hook(); + let beamlines: ArrayFieldState = beamlinesHandle.value as ArrayFieldState; + + let [hoveredBeamline, updateHoveredBeamline] = useState(undefined); + let selectBeamline = (id: number) => { + if(id !== selectedBeamline) { + selectedBeamlineIdHandle.write(id, store.getState(), dispatch); + } + } + + return ( + + + + + + + + + + + { + beamlines.map(bl => bl.item).map(bl => { + let name = bl.name as string; + let id = bl.id as number; + let isHovered = hoveredBeamline === id; + let isSelected = selectedBeamline === id; + return ( + updateHoveredBeamline(id)} onMouseLeave={() => isHovered ? updateHoveredBeamline(undefined) : undefined} style={ + { + backgroundColor: isSelected ? "#dff0d8" : undefined, + /*filter: isHovered ? "brightness(75%)" : undefined*/ + } + }> + + + + + + ) + }) + } + +
+ Name + + Description + + Length + + Bend +
+ {`${name}`} + + {/* TODO: description */} + + {(bl.length as number).toPrecision(4)} + + + {isHovered ? ( + + ) : (bl.angle as number).toPrecision(4)} +
+ ) + } +} diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index e392fd2c33..ec5ee9c917 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -40,12 +40,10 @@ export class NavBarModalButton extends Layout { } component = (props: LayoutProps<{}>) => { - let simulationInfoPromise = useContext(CSimulationInfoPromise); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; let [modalShown, updateModalShown] = useState(false); let dispatch = useDispatch(); let store = useStore(); - let appWrapper = useContext(CAppWrapper); let title = interpolate(this.config.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); let modalTitle = interpolate(this.config.modal.title).withDependencies(formHandleFactory, StoreTypes.Models).raw(); @@ -53,8 +51,6 @@ export class NavBarModalButton extends Layout { let { submit: _submit, cancel: _cancel } = formActionFunctions({ formHandleFactory, store, - simulationInfoPromise, - appWrapper, dispatch }); diff --git a/react/src/layout/shadow/beamline.tsx b/react/src/layout/shadow/beamline.tsx index 2e111070a5..ccaeb8c759 100644 --- a/react/src/layout/shadow/beamline.tsx +++ b/react/src/layout/shadow/beamline.tsx @@ -49,7 +49,6 @@ export function ShadowBeamlineItem(props: { index: number, baseElement: ShadowBe let routeHelper = useContext(CRouteHelper); let store = useStore(); - let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); let handleFactory = useContext(CHandleFactory); let createHandleFactory = () => new FormStateHandleFactory(schema, new HandleFactoryWithArrayAliases(schema, aliases, handleFactory)) @@ -59,15 +58,11 @@ export function ShadowBeamlineItem(props: { index: number, baseElement: ShadowBe } let [isHover, updateIsHover] = useState(false); - //aliasedHandleFactory.useUpdates(BeamlineItem); let dispatch = useDispatch(); - let appWrapper = useContext(CAppWrapper); let actionFunctions = formActionFunctions({ formHandleFactory: aliasedHandleFactory, store, - simulationInfoPromise, - appWrapper, dispatch }); @@ -130,12 +125,10 @@ export class ShadowBeamlineLayout extends Layout { component: FunctionComponent<{ [key: string]: any; }> = (props: LayoutProps<{}>) => { let routeHelper = useContext(CRouteHelper); let store = useStore(); - let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); let dispatch = useDispatch(); let formHandleFactory = useContext(CHandleFactory) as FormStateHandleFactory; formHandleFactory.useUpdates(ShadowBeamlineLayout); - let appWrapper = useContext(CAppWrapper); let beamlineDependency: Dependency = new Dependency(this.config.beamlineDependency); @@ -215,8 +208,6 @@ export class ShadowBeamlineLayout extends Layout { let { submit: _submit, cancel: _cancel } = formActionFunctions({ formHandleFactory, store, - simulationInfoPromise, - appWrapper, dispatch }); diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 402f342637..3b45817aa5 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -111,6 +111,10 @@ } }, "simulation": { + "activeBeamlineId": { + "displayName": "Active Beamline ID", + "type": "Integer" + }, "enableParticleTracking": { "displayName": "Particle Tracking", "type": "Boolean", @@ -6501,1080 +6505,1104 @@ "padding": ".5em", "items": [ { - "layout": "madxBeamlineElements", + "layout": "panel", "config": { - "elementsDependency": "elements.elements", - "templateGroups": [ - { - "name": "Basic", - "types": ["SBEND", "RBEND", "DRIFT", "COLLIMATOR", "ECOLLIMATOR", "RCOLLIMATOR", "KICKER", "MARKER", "QUADRUPOLE", "SEXTUPOLE"] - }, - { - "name": "Advanced", - "types": ["BEAMBEAM", "CHANGEREF", "CRABCAVITY", "DIPEDGE", "HACDIPOLE", "HKICKER", "HMONITOR", "INSTRUMENT", "MATRIX", "MONITOR", "MULTIPOLE", "NLLENS", "OCTUPOLE", "PLACEHOLDER", "RFCAVITY", "RFMULTIPOLE", "SOLENOID", "SROTATION", "TRANSLATION", "TWCAVITY", "VACDIPOLE", "VKICKER", "VMONITOR", "XROTATION", "YROTATION"] - }, + "title": "Beamlines", + "basic": [ { - "name": "All Elements", - "types": ["SBEND", "RBEND", "DRIFT", "COLLIMATOR", "ECOLLIMATOR", "RCOLLIMATOR", "KICKER", "MARKER", "QUADRUPOLE", "SEXTUPOLE", "BEAMBEAM", "CHANGEREF", "CRABCAVITY", "DIPEDGE", "HACDIPOLE", "HKICKER", "HMONITOR", "INSTRUMENT", "MATRIX", "MONITOR", "MULTIPOLE", "NLLENS", "OCTUPOLE", "PLACEHOLDER", "RFCAVITY", "RFMULTIPOLE", "SOLENOID", "SROTATION", "TRANSLATION", "TWCAVITY", "VACDIPOLE", "VKICKER", "VMONITOR", "XROTATION", "YROTATION"] + "layout": "madxBeamlinesPicker", + "config": { + "selectedBeamlineDependency": "simulation.activeBeamlineId", + "beamlinesDependency": "lattice.beamlines" + } } - ], - "elementTemplates": [ - { - "type": "BEAMBEAM", - "name": "BEAMBEAM", - "modelName": "BEAMBEAM", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "BEAMBEAM.name", - "BEAMBEAM.sigx", - "BEAMBEAM.sigy", - "BEAMBEAM.xma", - "BEAMBEAM.yma", - "BEAMBEAM.charge", - "BEAMBEAM.bbshape", - "BEAMBEAM.width", - "BEAMBEAM.bbdir", - "BEAMBEAM.apertype", - "BEAMBEAM.aperture", - "BEAMBEAM.aper_offset", - "BEAMBEAM.aper_tol" - ] - } - } - ] - }, + ] + } + }, + { + "layout": "panel", + "config": { + "title": "Beamline Elements", + "basic": [ { - "type": "CHANGEREF", - "name": "CHANGEREF", - "modelName": "CHANGEREF", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "CHANGEREF.name", - "CHANGEREF.patch_ang", - "CHANGEREF.patch_trans", - "CHANGEREF.apertype", - "CHANGEREF.aperture", - "CHANGEREF.aper_offset", - "CHANGEREF.aper_tol" - ] + "layout": "madxBeamlineElements", + "config": { + "elementsDependency": "elements.elements", + "templateGroups": [ + { + "name": "Basic", + "types": ["SBEND", "RBEND", "DRIFT", "COLLIMATOR", "ECOLLIMATOR", "RCOLLIMATOR", "KICKER", "MARKER", "QUADRUPOLE", "SEXTUPOLE"] + }, + { + "name": "Advanced", + "types": ["BEAMBEAM", "CHANGEREF", "CRABCAVITY", "DIPEDGE", "HACDIPOLE", "HKICKER", "HMONITOR", "INSTRUMENT", "MATRIX", "MONITOR", "MULTIPOLE", "NLLENS", "OCTUPOLE", "PLACEHOLDER", "RFCAVITY", "RFMULTIPOLE", "SOLENOID", "SROTATION", "TRANSLATION", "TWCAVITY", "VACDIPOLE", "VKICKER", "VMONITOR", "XROTATION", "YROTATION"] + }, + { + "name": "All Elements", + "types": ["SBEND", "RBEND", "DRIFT", "COLLIMATOR", "ECOLLIMATOR", "RCOLLIMATOR", "KICKER", "MARKER", "QUADRUPOLE", "SEXTUPOLE", "BEAMBEAM", "CHANGEREF", "CRABCAVITY", "DIPEDGE", "HACDIPOLE", "HKICKER", "HMONITOR", "INSTRUMENT", "MATRIX", "MONITOR", "MULTIPOLE", "NLLENS", "OCTUPOLE", "PLACEHOLDER", "RFCAVITY", "RFMULTIPOLE", "SOLENOID", "SROTATION", "TRANSLATION", "TWCAVITY", "VACDIPOLE", "VKICKER", "VMONITOR", "XROTATION", "YROTATION"] } - } - ] - }, - { - "type": "COLLIMATOR", - "name": "COLLIMATOR", - "modelName": "COLLIMATOR", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "COLLIMATOR.name", - "COLLIMATOR.l", - "COLLIMATOR.apertype", - "COLLIMATOR.aperture", - "COLLIMATOR.aper_offset", - "COLLIMATOR.aper_tol" + ], + "elementTemplates": [ + { + "type": "BEAMBEAM", + "name": "BEAMBEAM", + "modelName": "BEAMBEAM", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "BEAMBEAM.name", + "BEAMBEAM.sigx", + "BEAMBEAM.sigy", + "BEAMBEAM.xma", + "BEAMBEAM.yma", + "BEAMBEAM.charge", + "BEAMBEAM.bbshape", + "BEAMBEAM.width", + "BEAMBEAM.bbdir", + "BEAMBEAM.apertype", + "BEAMBEAM.aperture", + "BEAMBEAM.aper_offset", + "BEAMBEAM.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "CRABCAVITY", - "name": "CRABCAVITY", - "modelName": "CRABCAVITY", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "CRABCAVITY.name", - "CRABCAVITY.l", - "CRABCAVITY.volt", - "CRABCAVITY.lag", - "CRABCAVITY.freq", - "CRABCAVITY.rv1", - "CRABCAVITY.rv2", - "CRABCAVITY.rv3", - "CRABCAVITY.rv4", - "CRABCAVITY.rph1", - "CRABCAVITY.rph2", - "CRABCAVITY.lagf", - "CRABCAVITY.apertype", - "CRABCAVITY.aperture", - "CRABCAVITY.aper_offset", - "CRABCAVITY.aper_tol" + }, + { + "type": "CHANGEREF", + "name": "CHANGEREF", + "modelName": "CHANGEREF", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CHANGEREF.name", + "CHANGEREF.patch_ang", + "CHANGEREF.patch_trans", + "CHANGEREF.apertype", + "CHANGEREF.aperture", + "CHANGEREF.aper_offset", + "CHANGEREF.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "DIPEDGE", - "name": "DIPEDGE", - "modelName": "DIPEDGE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "DIPEDGE.name", - "DIPEDGE.h", - "DIPEDGE.e1", - "DIPEDGE.fint", - "DIPEDGE.hgap", - "DIPEDGE.tilt", - "DIPEDGE.apertype", - "DIPEDGE.aperture", - "DIPEDGE.aper_offset", - "DIPEDGE.aper_tol" + }, + { + "type": "COLLIMATOR", + "name": "COLLIMATOR", + "modelName": "COLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "COLLIMATOR.name", + "COLLIMATOR.l", + "COLLIMATOR.apertype", + "COLLIMATOR.aperture", + "COLLIMATOR.aper_offset", + "COLLIMATOR.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "DRIFT", - "name": "DRIFT", - "modelName": "DRIFT", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "DRIFT.name", - "DRIFT.l" + }, + { + "type": "CRABCAVITY", + "name": "CRABCAVITY", + "modelName": "CRABCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CRABCAVITY.name", + "CRABCAVITY.l", + "CRABCAVITY.volt", + "CRABCAVITY.lag", + "CRABCAVITY.freq", + "CRABCAVITY.rv1", + "CRABCAVITY.rv2", + "CRABCAVITY.rv3", + "CRABCAVITY.rv4", + "CRABCAVITY.rph1", + "CRABCAVITY.rph2", + "CRABCAVITY.lagf", + "CRABCAVITY.apertype", + "CRABCAVITY.aperture", + "CRABCAVITY.aper_offset", + "CRABCAVITY.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "ECOLLIMATOR", - "name": "ECOLLIMATOR", - "modelName": "ECOLLIMATOR", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "ECOLLIMATOR.name", - "ECOLLIMATOR.l", - "ECOLLIMATOR.xsize", - "ECOLLIMATOR.ysize", - "ECOLLIMATOR.apertype", - "ECOLLIMATOR.aperture", - "ECOLLIMATOR.aper_offset", - "ECOLLIMATOR.aper_tol" + }, + { + "type": "DIPEDGE", + "name": "DIPEDGE", + "modelName": "DIPEDGE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DIPEDGE.name", + "DIPEDGE.h", + "DIPEDGE.e1", + "DIPEDGE.fint", + "DIPEDGE.hgap", + "DIPEDGE.tilt", + "DIPEDGE.apertype", + "DIPEDGE.aperture", + "DIPEDGE.aper_offset", + "DIPEDGE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "HACDIPOLE", - "name": "HACDIPOLE", - "modelName": "HACDIPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HACDIPOLE.name", - "HACDIPOLE.l", - "HACDIPOLE.volt", - "HACDIPOLE.freq", - "HACDIPOLE.lag", - "HACDIPOLE.ramp1", - "HACDIPOLE.ramp2", - "HACDIPOLE.ramp3", - "HACDIPOLE.ramp4", - "HACDIPOLE.apertype", - "HACDIPOLE.aperture", - "HACDIPOLE.aper_offset", - "HACDIPOLE.aper_tol" + }, + { + "type": "DRIFT", + "name": "DRIFT", + "modelName": "DRIFT", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DRIFT.name", + "DRIFT.l" + ] + } + } ] - } - } - ] - }, - { - "type": "HKICKER", - "name": "HKICKER", - "modelName": "HKICKER", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HKICKER.name", - "HKICKER.l", - "HKICKER.kick", - "HKICKER.tilt", - "HKICKER.apertype", - "HKICKER.aperture", - "HKICKER.aper_offset", - "HKICKER.aper_tol" + }, + { + "type": "ECOLLIMATOR", + "name": "ECOLLIMATOR", + "modelName": "ECOLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "ECOLLIMATOR.name", + "ECOLLIMATOR.l", + "ECOLLIMATOR.xsize", + "ECOLLIMATOR.ysize", + "ECOLLIMATOR.apertype", + "ECOLLIMATOR.aperture", + "ECOLLIMATOR.aper_offset", + "ECOLLIMATOR.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "HMONITOR", - "name": "HMONITOR", - "modelName": "HMONITOR", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "HMONITOR.name", - "HMONITOR.l", - "HMONITOR.apertype", - "HMONITOR.aperture", - "HMONITOR.aper_offset", - "HMONITOR.aper_tol" + }, + { + "type": "HACDIPOLE", + "name": "HACDIPOLE", + "modelName": "HACDIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HACDIPOLE.name", + "HACDIPOLE.l", + "HACDIPOLE.volt", + "HACDIPOLE.freq", + "HACDIPOLE.lag", + "HACDIPOLE.ramp1", + "HACDIPOLE.ramp2", + "HACDIPOLE.ramp3", + "HACDIPOLE.ramp4", + "HACDIPOLE.apertype", + "HACDIPOLE.aperture", + "HACDIPOLE.aper_offset", + "HACDIPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "INSTRUMENT", - "name": "INSTRUMENT", - "modelName": "INSTRUMENT", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "INSTRUMENT.name", - "INSTRUMENT.l", - "INSTRUMENT.apertype", - "INSTRUMENT.aperture", - "INSTRUMENT.aper_offset", - "INSTRUMENT.aper_tol" + }, + { + "type": "HKICKER", + "name": "HKICKER", + "modelName": "HKICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HKICKER.name", + "HKICKER.l", + "HKICKER.kick", + "HKICKER.tilt", + "HKICKER.apertype", + "HKICKER.aperture", + "HKICKER.aper_offset", + "HKICKER.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "KICKER", - "name": "KICKER", - "modelName": "KICKER", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "KICKER.name", - "KICKER.l", - "KICKER.hkick", - "KICKER.vkick", - "KICKER.tilt", - "KICKER.apertype", - "KICKER.aperture", - "KICKER.aper_offset", - "KICKER.aper_tol" + }, + { + "type": "HMONITOR", + "name": "HMONITOR", + "modelName": "HMONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HMONITOR.name", + "HMONITOR.l", + "HMONITOR.apertype", + "HMONITOR.aperture", + "HMONITOR.aper_offset", + "HMONITOR.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "MARKER", - "name": "MARKER", - "modelName": "MARKER", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MARKER.name", - "MARKER.apertype", - "MARKER.aperture", - "MARKER.aper_offset", - "MARKER.aper_tol" + }, + { + "type": "INSTRUMENT", + "name": "INSTRUMENT", + "modelName": "INSTRUMENT", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "INSTRUMENT.name", + "INSTRUMENT.l", + "INSTRUMENT.apertype", + "INSTRUMENT.aperture", + "INSTRUMENT.aper_offset", + "INSTRUMENT.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "MATRIX", - "name": "MATRIX", - "modelName": "MATRIX", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MATRIX.name", - "MATRIX.l", - "MATRIX.kick1", - "MATRIX.kick6", - "MATRIX.rm11", - "MATRIX.rm66", - "MATRIX.tm111", - "MATRIX.tm666", - "MATRIX.kick2", - "MATRIX.kick3", - "MATRIX.kick4", - "MATRIX.kick5", - "MATRIX.rm12", - "MATRIX.rm13", - "MATRIX.rm14", - "MATRIX.rm15", - "MATRIX.rm16", - "MATRIX.rm21", - "MATRIX.rm22", - "MATRIX.rm23", - "MATRIX.rm24", - "MATRIX.rm25", - "MATRIX.rm26", - "MATRIX.rm31", - "MATRIX.rm32", - "MATRIX.rm33", - "MATRIX.rm34", - "MATRIX.rm35", - "MATRIX.rm36", - "MATRIX.rm41", - "MATRIX.rm42", - "MATRIX.rm43", - "MATRIX.rm44", - "MATRIX.rm45", - "MATRIX.rm46", - "MATRIX.rm51", - "MATRIX.rm52", - "MATRIX.rm53", - "MATRIX.rm54", - "MATRIX.rm55", - "MATRIX.rm56", - "MATRIX.rm61", - "MATRIX.rm62", - "MATRIX.rm63", - "MATRIX.rm64", - "MATRIX.rm65", - "MATRIX.tm112", - "MATRIX.tm113", - "MATRIX.tm114", - "MATRIX.tm115", - "MATRIX.tm116", - "MATRIX.tm121", - "MATRIX.tm122", - "MATRIX.tm123", - "MATRIX.tm124", - "MATRIX.tm125", - "MATRIX.tm126", - "MATRIX.tm131", - "MATRIX.tm132", - "MATRIX.tm133", - "MATRIX.tm134", - "MATRIX.tm135", - "MATRIX.tm136", - "MATRIX.tm141", - "MATRIX.tm142", - "MATRIX.tm143", - "MATRIX.tm144", - "MATRIX.tm145", - "MATRIX.tm146", - "MATRIX.tm151", - "MATRIX.tm152", - "MATRIX.tm153", - "MATRIX.tm154", - "MATRIX.tm155", - "MATRIX.tm156", - "MATRIX.tm161", - "MATRIX.tm162", - "MATRIX.tm163", - "MATRIX.tm164", - "MATRIX.tm165", - "MATRIX.tm166", - "MATRIX.tm211", - "MATRIX.tm212", - "MATRIX.tm213", - "MATRIX.tm214", - "MATRIX.tm215", - "MATRIX.tm216", - "MATRIX.tm221", - "MATRIX.tm222", - "MATRIX.tm223", - "MATRIX.tm224", - "MATRIX.tm225", - "MATRIX.tm226", - "MATRIX.tm231", - "MATRIX.tm232", - "MATRIX.tm233", - "MATRIX.tm234", - "MATRIX.tm235", - "MATRIX.tm236", - "MATRIX.tm241", - "MATRIX.tm242", - "MATRIX.tm243", - "MATRIX.tm244", - "MATRIX.tm245", - "MATRIX.tm246", - "MATRIX.tm251", - "MATRIX.tm252", - "MATRIX.tm253", - "MATRIX.tm254", - "MATRIX.tm255", - "MATRIX.tm256", - "MATRIX.tm261", - "MATRIX.tm262", - "MATRIX.tm263", - "MATRIX.tm264", - "MATRIX.tm265", - "MATRIX.tm266", - "MATRIX.tm311", - "MATRIX.tm312", - "MATRIX.tm313", - "MATRIX.tm314", - "MATRIX.tm315", - "MATRIX.tm316", - "MATRIX.tm321", - "MATRIX.tm322", - "MATRIX.tm323", - "MATRIX.tm324", - "MATRIX.tm325", - "MATRIX.tm326", - "MATRIX.tm331", - "MATRIX.tm332", - "MATRIX.tm333", - "MATRIX.tm334", - "MATRIX.tm335", - "MATRIX.tm336", - "MATRIX.tm341", - "MATRIX.tm342", - "MATRIX.tm343", - "MATRIX.tm344", - "MATRIX.tm345", - "MATRIX.tm346", - "MATRIX.tm351", - "MATRIX.tm352", - "MATRIX.tm353", - "MATRIX.tm354", - "MATRIX.tm355", - "MATRIX.tm356", - "MATRIX.tm361", - "MATRIX.tm362", - "MATRIX.tm363", - "MATRIX.tm364", - "MATRIX.tm365", - "MATRIX.tm366", - "MATRIX.tm411", - "MATRIX.tm412", - "MATRIX.tm413", - "MATRIX.tm414", - "MATRIX.tm415", - "MATRIX.tm416", - "MATRIX.tm421", - "MATRIX.tm422", - "MATRIX.tm423", - "MATRIX.tm424", - "MATRIX.tm425", - "MATRIX.tm426", - "MATRIX.tm431", - "MATRIX.tm432", - "MATRIX.tm433", - "MATRIX.tm434", - "MATRIX.tm435", - "MATRIX.tm436", - "MATRIX.tm441", - "MATRIX.tm442", - "MATRIX.tm443", - "MATRIX.tm444", - "MATRIX.tm445", - "MATRIX.tm446", - "MATRIX.tm451", - "MATRIX.tm452", - "MATRIX.tm453", - "MATRIX.tm454", - "MATRIX.tm455", - "MATRIX.tm456", - "MATRIX.tm461", - "MATRIX.tm462", - "MATRIX.tm463", - "MATRIX.tm464", - "MATRIX.tm465", - "MATRIX.tm466", - "MATRIX.tm511", - "MATRIX.tm512", - "MATRIX.tm513", - "MATRIX.tm514", - "MATRIX.tm515", - "MATRIX.tm516", - "MATRIX.tm521", - "MATRIX.tm522", - "MATRIX.tm523", - "MATRIX.tm524", - "MATRIX.tm525", - "MATRIX.tm526", - "MATRIX.tm531", - "MATRIX.tm532", - "MATRIX.tm533", - "MATRIX.tm534", - "MATRIX.tm535", - "MATRIX.tm536", - "MATRIX.tm541", - "MATRIX.tm542", - "MATRIX.tm543", - "MATRIX.tm544", - "MATRIX.tm545", - "MATRIX.tm546", - "MATRIX.tm551", - "MATRIX.tm552", - "MATRIX.tm553", - "MATRIX.tm554", - "MATRIX.tm555", - "MATRIX.tm556", - "MATRIX.tm561", - "MATRIX.tm562", - "MATRIX.tm563", - "MATRIX.tm564", - "MATRIX.tm565", - "MATRIX.tm566", - "MATRIX.tm611", - "MATRIX.tm612", - "MATRIX.tm613", - "MATRIX.tm614", - "MATRIX.tm615", - "MATRIX.tm616", - "MATRIX.tm621", - "MATRIX.tm622", - "MATRIX.tm623", - "MATRIX.tm624", - "MATRIX.tm625", - "MATRIX.tm626", - "MATRIX.tm631", - "MATRIX.tm632", - "MATRIX.tm633", - "MATRIX.tm634", - "MATRIX.tm635", - "MATRIX.tm636", - "MATRIX.tm641", - "MATRIX.tm642", - "MATRIX.tm643", - "MATRIX.tm644", - "MATRIX.tm645", - "MATRIX.tm646", - "MATRIX.tm651", - "MATRIX.tm652", - "MATRIX.tm653", - "MATRIX.tm654", - "MATRIX.tm655", - "MATRIX.tm656", - "MATRIX.tm661", - "MATRIX.tm662", - "MATRIX.tm663", - "MATRIX.tm664", - "MATRIX.tm665" + }, + { + "type": "KICKER", + "name": "KICKER", + "modelName": "KICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "KICKER.name", + "KICKER.l", + "KICKER.hkick", + "KICKER.vkick", + "KICKER.tilt", + "KICKER.apertype", + "KICKER.aperture", + "KICKER.aper_offset", + "KICKER.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "MONITOR", - "name": "MONITOR", - "modelName": "MONITOR", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MONITOR.name", - "MONITOR.l", - "MONITOR.apertype", - "MONITOR.aperture", - "MONITOR.aper_offset", - "MONITOR.aper_tol" + }, + { + "type": "MARKER", + "name": "MARKER", + "modelName": "MARKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MARKER.name", + "MARKER.apertype", + "MARKER.aperture", + "MARKER.aper_offset", + "MARKER.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "MULTIPOLE", - "name": "MULTIPOLE", - "modelName": "MULTIPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "MULTIPOLE.name", - "MULTIPOLE.lrad", - "MULTIPOLE.tilt", - "MULTIPOLE.knl", - "MULTIPOLE.ksl", - "MULTIPOLE.apertype", - "MULTIPOLE.aperture", - "MULTIPOLE.aper_offset", - "MULTIPOLE.aper_tol" + }, + { + "type": "MATRIX", + "name": "MATRIX", + "modelName": "MATRIX", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MATRIX.name", + "MATRIX.l", + "MATRIX.kick1", + "MATRIX.kick6", + "MATRIX.rm11", + "MATRIX.rm66", + "MATRIX.tm111", + "MATRIX.tm666", + "MATRIX.kick2", + "MATRIX.kick3", + "MATRIX.kick4", + "MATRIX.kick5", + "MATRIX.rm12", + "MATRIX.rm13", + "MATRIX.rm14", + "MATRIX.rm15", + "MATRIX.rm16", + "MATRIX.rm21", + "MATRIX.rm22", + "MATRIX.rm23", + "MATRIX.rm24", + "MATRIX.rm25", + "MATRIX.rm26", + "MATRIX.rm31", + "MATRIX.rm32", + "MATRIX.rm33", + "MATRIX.rm34", + "MATRIX.rm35", + "MATRIX.rm36", + "MATRIX.rm41", + "MATRIX.rm42", + "MATRIX.rm43", + "MATRIX.rm44", + "MATRIX.rm45", + "MATRIX.rm46", + "MATRIX.rm51", + "MATRIX.rm52", + "MATRIX.rm53", + "MATRIX.rm54", + "MATRIX.rm55", + "MATRIX.rm56", + "MATRIX.rm61", + "MATRIX.rm62", + "MATRIX.rm63", + "MATRIX.rm64", + "MATRIX.rm65", + "MATRIX.tm112", + "MATRIX.tm113", + "MATRIX.tm114", + "MATRIX.tm115", + "MATRIX.tm116", + "MATRIX.tm121", + "MATRIX.tm122", + "MATRIX.tm123", + "MATRIX.tm124", + "MATRIX.tm125", + "MATRIX.tm126", + "MATRIX.tm131", + "MATRIX.tm132", + "MATRIX.tm133", + "MATRIX.tm134", + "MATRIX.tm135", + "MATRIX.tm136", + "MATRIX.tm141", + "MATRIX.tm142", + "MATRIX.tm143", + "MATRIX.tm144", + "MATRIX.tm145", + "MATRIX.tm146", + "MATRIX.tm151", + "MATRIX.tm152", + "MATRIX.tm153", + "MATRIX.tm154", + "MATRIX.tm155", + "MATRIX.tm156", + "MATRIX.tm161", + "MATRIX.tm162", + "MATRIX.tm163", + "MATRIX.tm164", + "MATRIX.tm165", + "MATRIX.tm166", + "MATRIX.tm211", + "MATRIX.tm212", + "MATRIX.tm213", + "MATRIX.tm214", + "MATRIX.tm215", + "MATRIX.tm216", + "MATRIX.tm221", + "MATRIX.tm222", + "MATRIX.tm223", + "MATRIX.tm224", + "MATRIX.tm225", + "MATRIX.tm226", + "MATRIX.tm231", + "MATRIX.tm232", + "MATRIX.tm233", + "MATRIX.tm234", + "MATRIX.tm235", + "MATRIX.tm236", + "MATRIX.tm241", + "MATRIX.tm242", + "MATRIX.tm243", + "MATRIX.tm244", + "MATRIX.tm245", + "MATRIX.tm246", + "MATRIX.tm251", + "MATRIX.tm252", + "MATRIX.tm253", + "MATRIX.tm254", + "MATRIX.tm255", + "MATRIX.tm256", + "MATRIX.tm261", + "MATRIX.tm262", + "MATRIX.tm263", + "MATRIX.tm264", + "MATRIX.tm265", + "MATRIX.tm266", + "MATRIX.tm311", + "MATRIX.tm312", + "MATRIX.tm313", + "MATRIX.tm314", + "MATRIX.tm315", + "MATRIX.tm316", + "MATRIX.tm321", + "MATRIX.tm322", + "MATRIX.tm323", + "MATRIX.tm324", + "MATRIX.tm325", + "MATRIX.tm326", + "MATRIX.tm331", + "MATRIX.tm332", + "MATRIX.tm333", + "MATRIX.tm334", + "MATRIX.tm335", + "MATRIX.tm336", + "MATRIX.tm341", + "MATRIX.tm342", + "MATRIX.tm343", + "MATRIX.tm344", + "MATRIX.tm345", + "MATRIX.tm346", + "MATRIX.tm351", + "MATRIX.tm352", + "MATRIX.tm353", + "MATRIX.tm354", + "MATRIX.tm355", + "MATRIX.tm356", + "MATRIX.tm361", + "MATRIX.tm362", + "MATRIX.tm363", + "MATRIX.tm364", + "MATRIX.tm365", + "MATRIX.tm366", + "MATRIX.tm411", + "MATRIX.tm412", + "MATRIX.tm413", + "MATRIX.tm414", + "MATRIX.tm415", + "MATRIX.tm416", + "MATRIX.tm421", + "MATRIX.tm422", + "MATRIX.tm423", + "MATRIX.tm424", + "MATRIX.tm425", + "MATRIX.tm426", + "MATRIX.tm431", + "MATRIX.tm432", + "MATRIX.tm433", + "MATRIX.tm434", + "MATRIX.tm435", + "MATRIX.tm436", + "MATRIX.tm441", + "MATRIX.tm442", + "MATRIX.tm443", + "MATRIX.tm444", + "MATRIX.tm445", + "MATRIX.tm446", + "MATRIX.tm451", + "MATRIX.tm452", + "MATRIX.tm453", + "MATRIX.tm454", + "MATRIX.tm455", + "MATRIX.tm456", + "MATRIX.tm461", + "MATRIX.tm462", + "MATRIX.tm463", + "MATRIX.tm464", + "MATRIX.tm465", + "MATRIX.tm466", + "MATRIX.tm511", + "MATRIX.tm512", + "MATRIX.tm513", + "MATRIX.tm514", + "MATRIX.tm515", + "MATRIX.tm516", + "MATRIX.tm521", + "MATRIX.tm522", + "MATRIX.tm523", + "MATRIX.tm524", + "MATRIX.tm525", + "MATRIX.tm526", + "MATRIX.tm531", + "MATRIX.tm532", + "MATRIX.tm533", + "MATRIX.tm534", + "MATRIX.tm535", + "MATRIX.tm536", + "MATRIX.tm541", + "MATRIX.tm542", + "MATRIX.tm543", + "MATRIX.tm544", + "MATRIX.tm545", + "MATRIX.tm546", + "MATRIX.tm551", + "MATRIX.tm552", + "MATRIX.tm553", + "MATRIX.tm554", + "MATRIX.tm555", + "MATRIX.tm556", + "MATRIX.tm561", + "MATRIX.tm562", + "MATRIX.tm563", + "MATRIX.tm564", + "MATRIX.tm565", + "MATRIX.tm566", + "MATRIX.tm611", + "MATRIX.tm612", + "MATRIX.tm613", + "MATRIX.tm614", + "MATRIX.tm615", + "MATRIX.tm616", + "MATRIX.tm621", + "MATRIX.tm622", + "MATRIX.tm623", + "MATRIX.tm624", + "MATRIX.tm625", + "MATRIX.tm626", + "MATRIX.tm631", + "MATRIX.tm632", + "MATRIX.tm633", + "MATRIX.tm634", + "MATRIX.tm635", + "MATRIX.tm636", + "MATRIX.tm641", + "MATRIX.tm642", + "MATRIX.tm643", + "MATRIX.tm644", + "MATRIX.tm645", + "MATRIX.tm646", + "MATRIX.tm651", + "MATRIX.tm652", + "MATRIX.tm653", + "MATRIX.tm654", + "MATRIX.tm655", + "MATRIX.tm656", + "MATRIX.tm661", + "MATRIX.tm662", + "MATRIX.tm663", + "MATRIX.tm664", + "MATRIX.tm665" + ] + } + } ] - } - } - ] - }, - { - "type": "NLLENS", - "name": "NLLENS", - "modelName": "NLLENS", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "NLLENS.name", - "NLLENS.knll", - "NLLENS.cnll", - "NLLENS.apertype", - "NLLENS.aperture", - "NLLENS.aper_offset", - "NLLENS.aper_tol" + }, + { + "type": "MONITOR", + "name": "MONITOR", + "modelName": "MONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MONITOR.name", + "MONITOR.l", + "MONITOR.apertype", + "MONITOR.aperture", + "MONITOR.aper_offset", + "MONITOR.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "OCTUPOLE", - "name": "OCTUPOLE", - "modelName": "OCTUPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "OCTUPOLE.name", - "OCTUPOLE.l", - "OCTUPOLE.k3", - "OCTUPOLE.k3s", - "OCTUPOLE.tilt", - "OCTUPOLE.apertype", - "OCTUPOLE.aperture", - "OCTUPOLE.aper_offset", - "OCTUPOLE.aper_tol" + }, + { + "type": "MULTIPOLE", + "name": "MULTIPOLE", + "modelName": "MULTIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MULTIPOLE.name", + "MULTIPOLE.lrad", + "MULTIPOLE.tilt", + "MULTIPOLE.knl", + "MULTIPOLE.ksl", + "MULTIPOLE.apertype", + "MULTIPOLE.aperture", + "MULTIPOLE.aper_offset", + "MULTIPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "PLACEHOLDER", - "name": "PLACEHOLDER", - "modelName": "PLACEHOLDER", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "PLACEHOLDER.name", - "PLACEHOLDER.l", - "PLACEHOLDER.apertype", - "PLACEHOLDER.aperture", - "PLACEHOLDER.aper_offset", - "PLACEHOLDER.aper_tol" + }, + { + "type": "NLLENS", + "name": "NLLENS", + "modelName": "NLLENS", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "NLLENS.name", + "NLLENS.knll", + "NLLENS.cnll", + "NLLENS.apertype", + "NLLENS.aperture", + "NLLENS.aper_offset", + "NLLENS.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "QUADRUPOLE", - "name": "QUADRUPOLE", - "modelName": "QUADRUPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "QUADRUPOLE.name", - "QUADRUPOLE.l", - "QUADRUPOLE.k1", - "QUADRUPOLE.k1s", - "QUADRUPOLE.tilt", - "QUADRUPOLE.thick", - "QUADRUPOLE.apertype", - "QUADRUPOLE.aperture", - "QUADRUPOLE.aper_offset", - "QUADRUPOLE.aper_tol" + }, + { + "type": "OCTUPOLE", + "name": "OCTUPOLE", + "modelName": "OCTUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "OCTUPOLE.name", + "OCTUPOLE.l", + "OCTUPOLE.k3", + "OCTUPOLE.k3s", + "OCTUPOLE.tilt", + "OCTUPOLE.apertype", + "OCTUPOLE.aperture", + "OCTUPOLE.aper_offset", + "OCTUPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "RBEND", - "name": "RBEND", - "modelName": "RBEND", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RBEND.name", - "RBEND.l", - "RBEND.angle", - "RBEND.tilt", - "RBEND.k1", - "RBEND.k2", - "RBEND.e1", - "RBEND.e2", - "RBEND.fint", - "RBEND.fintx", - "RBEND.hgap", - "RBEND.h1", - "RBEND.h2", - "RBEND.add_angle", - "RBEND.thick", - "RBEND.apertype", - "RBEND.aperture", - "RBEND.aper_offset", - "RBEND.aper_tol" + }, + { + "type": "PLACEHOLDER", + "name": "PLACEHOLDER", + "modelName": "PLACEHOLDER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "PLACEHOLDER.name", + "PLACEHOLDER.l", + "PLACEHOLDER.apertype", + "PLACEHOLDER.aperture", + "PLACEHOLDER.aper_offset", + "PLACEHOLDER.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "RCOLLIMATOR", - "name": "RCOLLIMATOR", - "modelName": "RCOLLIMATOR", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RCOLLIMATOR.name", - "RCOLLIMATOR.l", - "RCOLLIMATOR.xsize", - "RCOLLIMATOR.ysize", - "RCOLLIMATOR.apertype", - "RCOLLIMATOR.aperture", - "RCOLLIMATOR.aper_offset", - "RCOLLIMATOR.aper_tol" + }, + { + "type": "QUADRUPOLE", + "name": "QUADRUPOLE", + "modelName": "QUADRUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "QUADRUPOLE.name", + "QUADRUPOLE.l", + "QUADRUPOLE.k1", + "QUADRUPOLE.k1s", + "QUADRUPOLE.tilt", + "QUADRUPOLE.thick", + "QUADRUPOLE.apertype", + "QUADRUPOLE.aperture", + "QUADRUPOLE.aper_offset", + "QUADRUPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "RFCAVITY", - "name": "RFCAVITY", - "modelName": "RFCAVITY", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RFCAVITY.name", - "RFCAVITY.l", - "RFCAVITY.volt", - "RFCAVITY.lag", - "RFCAVITY.harmon", - "RFCAVITY.freq", - "RFCAVITY.apertype", - "RFCAVITY.aperture", - "RFCAVITY.aper_offset", - "RFCAVITY.aper_tol" + }, + { + "type": "RBEND", + "name": "RBEND", + "modelName": "RBEND", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RBEND.name", + "RBEND.l", + "RBEND.angle", + "RBEND.tilt", + "RBEND.k1", + "RBEND.k2", + "RBEND.e1", + "RBEND.e2", + "RBEND.fint", + "RBEND.fintx", + "RBEND.hgap", + "RBEND.h1", + "RBEND.h2", + "RBEND.add_angle", + "RBEND.thick", + "RBEND.apertype", + "RBEND.aperture", + "RBEND.aper_offset", + "RBEND.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "RFMULTIPOLE", - "name": "RFMULTIPOLE", - "modelName": "RFMULTIPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "RFMULTIPOLE.name", - "RFMULTIPOLE.volt", - "RFMULTIPOLE.lag", - "RFMULTIPOLE.harmon", - "RFMULTIPOLE.freq", - "RFMULTIPOLE.lrad", - "RFMULTIPOLE.tilt", - "RFMULTIPOLE.knl", - "RFMULTIPOLE.ksl", - "RFMULTIPOLE.pnl", - "RFMULTIPOLE.psl", - "RFMULTIPOLE.apertype", - "RFMULTIPOLE.aperture", - "RFMULTIPOLE.aper_offset", - "RFMULTIPOLE.aper_tol" + }, + { + "type": "RCOLLIMATOR", + "name": "RCOLLIMATOR", + "modelName": "RCOLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RCOLLIMATOR.name", + "RCOLLIMATOR.l", + "RCOLLIMATOR.xsize", + "RCOLLIMATOR.ysize", + "RCOLLIMATOR.apertype", + "RCOLLIMATOR.aperture", + "RCOLLIMATOR.aper_offset", + "RCOLLIMATOR.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "SBEND", - "name": "SBEND", - "modelName": "SBEND", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SBEND.name", - "SBEND.l", - "SBEND.angle", - "SBEND.k1", - "SBEND.k2", - "SBEND.e1", - "SBEND.e2", - "SBEND.tilt", - "SBEND.h1", - "SBEND.h2", - "SBEND.hgap", - "SBEND.fint", - "SBEND.fintx", - "SBEND.thick", - "SBEND.apertype", - "SBEND.aperture", - "SBEND.aper_offset", - "SBEND.aper_tol" + }, + { + "type": "RFCAVITY", + "name": "RFCAVITY", + "modelName": "RFCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFCAVITY.name", + "RFCAVITY.l", + "RFCAVITY.volt", + "RFCAVITY.lag", + "RFCAVITY.harmon", + "RFCAVITY.freq", + "RFCAVITY.apertype", + "RFCAVITY.aperture", + "RFCAVITY.aper_offset", + "RFCAVITY.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "SEXTUPOLE", - "name": "SEXTUPOLE", - "modelName": "SEXTUPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SEXTUPOLE.name", - "SEXTUPOLE.l", - "SEXTUPOLE.k2", - "SEXTUPOLE.k2s", - "SEXTUPOLE.tilt", - "SEXTUPOLE.apertype", - "SEXTUPOLE.aperture", - "SEXTUPOLE.aper_offset", - "SEXTUPOLE.aper_tol" + }, + { + "type": "RFMULTIPOLE", + "name": "RFMULTIPOLE", + "modelName": "RFMULTIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFMULTIPOLE.name", + "RFMULTIPOLE.volt", + "RFMULTIPOLE.lag", + "RFMULTIPOLE.harmon", + "RFMULTIPOLE.freq", + "RFMULTIPOLE.lrad", + "RFMULTIPOLE.tilt", + "RFMULTIPOLE.knl", + "RFMULTIPOLE.ksl", + "RFMULTIPOLE.pnl", + "RFMULTIPOLE.psl", + "RFMULTIPOLE.apertype", + "RFMULTIPOLE.aperture", + "RFMULTIPOLE.aper_offset", + "RFMULTIPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "SOLENOID", - "name": "SOLENOID", - "modelName": "SOLENOID", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SOLENOID.name", - "SOLENOID.l", - "SOLENOID.ks", - "SOLENOID.ksi", - "SOLENOID.apertype", - "SOLENOID.aperture", - "SOLENOID.aper_offset", - "SOLENOID.aper_tol" + }, + { + "type": "SBEND", + "name": "SBEND", + "modelName": "SBEND", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SBEND.name", + "SBEND.l", + "SBEND.angle", + "SBEND.k1", + "SBEND.k2", + "SBEND.e1", + "SBEND.e2", + "SBEND.tilt", + "SBEND.h1", + "SBEND.h2", + "SBEND.hgap", + "SBEND.fint", + "SBEND.fintx", + "SBEND.thick", + "SBEND.apertype", + "SBEND.aperture", + "SBEND.aper_offset", + "SBEND.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "SROTATION", - "name": "SROTATION", - "modelName": "SROTATION", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "SROTATION.name", - "SROTATION.angle", - "SROTATION.apertype", - "SROTATION.aperture", - "SROTATION.aper_offset", - "SROTATION.aper_tol" + }, + { + "type": "SEXTUPOLE", + "name": "SEXTUPOLE", + "modelName": "SEXTUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SEXTUPOLE.name", + "SEXTUPOLE.l", + "SEXTUPOLE.k2", + "SEXTUPOLE.k2s", + "SEXTUPOLE.tilt", + "SEXTUPOLE.apertype", + "SEXTUPOLE.aperture", + "SEXTUPOLE.aper_offset", + "SEXTUPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "TRANSLATION", - "name": "TRANSLATION", - "modelName": "TRANSLATION", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "TRANSLATION.name", - "TRANSLATION.dx", - "TRANSLATION.dy", - "TRANSLATION.ds" + }, + { + "type": "SOLENOID", + "name": "SOLENOID", + "modelName": "SOLENOID", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SOLENOID.name", + "SOLENOID.l", + "SOLENOID.ks", + "SOLENOID.ksi", + "SOLENOID.apertype", + "SOLENOID.aperture", + "SOLENOID.aper_offset", + "SOLENOID.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "TWCAVITY", - "name": "TWCAVITY", - "modelName": "TWCAVITY", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "TWCAVITY.name", - "TWCAVITY.l", - "TWCAVITY.volt", - "TWCAVITY.freq", - "TWCAVITY.lag", - "TWCAVITY.psi", - "TWCAVITY.delta_lag", - "TWCAVITY.apertype", - "TWCAVITY.aperture", - "TWCAVITY.aper_offset", - "TWCAVITY.aper_tol" + }, + { + "type": "SROTATION", + "name": "SROTATION", + "modelName": "SROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SROTATION.name", + "SROTATION.angle", + "SROTATION.apertype", + "SROTATION.aperture", + "SROTATION.aper_offset", + "SROTATION.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "VACDIPOLE", - "name": "VACDIPOLE", - "modelName": "VACDIPOLE", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VACDIPOLE.name", - "VACDIPOLE.l", - "VACDIPOLE.volt", - "VACDIPOLE.freq", - "VACDIPOLE.lag", - "VACDIPOLE.ramp1", - "VACDIPOLE.ramp2", - "VACDIPOLE.ramp3", - "VACDIPOLE.ramp4", - "VACDIPOLE.apertype", - "VACDIPOLE.aperture", - "VACDIPOLE.aper_offset", - "VACDIPOLE.aper_tol" + }, + { + "type": "TRANSLATION", + "name": "TRANSLATION", + "modelName": "TRANSLATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TRANSLATION.name", + "TRANSLATION.dx", + "TRANSLATION.dy", + "TRANSLATION.ds" + ] + } + } ] - } - } - ] - }, - { - "type": "VKICKER", - "name": "VKICKER", - "modelName": "VKICKER", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VKICKER.name", - "VKICKER.l", - "VKICKER.kick", - "VKICKER.tilt", - "VKICKER.apertype", - "VKICKER.aperture", - "VKICKER.aper_offset", - "VKICKER.aper_tol" + }, + { + "type": "TWCAVITY", + "name": "TWCAVITY", + "modelName": "TWCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TWCAVITY.name", + "TWCAVITY.l", + "TWCAVITY.volt", + "TWCAVITY.freq", + "TWCAVITY.lag", + "TWCAVITY.psi", + "TWCAVITY.delta_lag", + "TWCAVITY.apertype", + "TWCAVITY.aperture", + "TWCAVITY.aper_offset", + "TWCAVITY.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "VMONITOR", - "name": "VMONITOR", - "modelName": "VMONITOR", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "VMONITOR.name", - "VMONITOR.l", - "VMONITOR.apertype", - "VMONITOR.aperture", - "VMONITOR.aper_offset", - "VMONITOR.aper_tol" + }, + { + "type": "VACDIPOLE", + "name": "VACDIPOLE", + "modelName": "VACDIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VACDIPOLE.name", + "VACDIPOLE.l", + "VACDIPOLE.volt", + "VACDIPOLE.freq", + "VACDIPOLE.lag", + "VACDIPOLE.ramp1", + "VACDIPOLE.ramp2", + "VACDIPOLE.ramp3", + "VACDIPOLE.ramp4", + "VACDIPOLE.apertype", + "VACDIPOLE.aperture", + "VACDIPOLE.aper_offset", + "VACDIPOLE.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "XROTATION", - "name": "XROTATION", - "modelName": "XROTATION", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "XROTATION.name", - "XROTATION.angle", - "XROTATION.apertype", - "XROTATION.aperture", - "XROTATION.aper_offset", - "XROTATION.aper_tol" + }, + { + "type": "VKICKER", + "name": "VKICKER", + "modelName": "VKICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VKICKER.name", + "VKICKER.l", + "VKICKER.kick", + "VKICKER.tilt", + "VKICKER.apertype", + "VKICKER.aperture", + "VKICKER.aper_offset", + "VKICKER.aper_tol" + ] + } + } ] - } - } - ] - }, - { - "type": "YROTATION", - "name": "YROTATION", - "modelName": "YROTATION", - "items": [ - { - "layout": "fieldList", - "config": { - "fields": [ - "YROTATION.name", - "YROTATION.angle", - "YROTATION.apertype", - "YROTATION.aperture", - "YROTATION.aper_offset", - "YROTATION.aper_tol" + }, + { + "type": "VMONITOR", + "name": "VMONITOR", + "modelName": "VMONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VMONITOR.name", + "VMONITOR.l", + "VMONITOR.apertype", + "VMONITOR.aperture", + "VMONITOR.aper_offset", + "VMONITOR.aper_tol" + ] + } + } + ] + }, + { + "type": "XROTATION", + "name": "XROTATION", + "modelName": "XROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "XROTATION.name", + "XROTATION.angle", + "XROTATION.apertype", + "XROTATION.aperture", + "XROTATION.aper_offset", + "XROTATION.aper_tol" + ] + } + } + ] + }, + { + "type": "YROTATION", + "name": "YROTATION", + "modelName": "YROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "YROTATION.name", + "YROTATION.angle", + "YROTATION.apertype", + "YROTATION.aperture", + "YROTATION.aper_offset", + "YROTATION.aper_tol" + ] + } + } ] } - } - ] + ] + } } ] } } + ] } } From 3c6ff833f27c4a0d881b75eee16022aa7902219a Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 5 May 2023 22:06:37 +0000 Subject: [PATCH 43/68] wip create beamline editor --- react/src/data/middleware/middleware.ts | 2 +- react/src/layout/layouts.ts | 8 +- react/src/layout/madx/allBeamlineElements.tsx | 243 ++++ react/src/layout/madx/beamlineElements.tsx | 275 +---- .../static/react-json/madx-schema.json | 1074 ++++++++++++++++- 5 files changed, 1378 insertions(+), 224 deletions(-) create mode 100644 react/src/layout/madx/allBeamlineElements.tsx diff --git a/react/src/data/middleware/middleware.ts b/react/src/data/middleware/middleware.ts index 89e9892ad2..afa6699368 100644 --- a/react/src/data/middleware/middleware.ts +++ b/react/src/data/middleware/middleware.ts @@ -1,5 +1,5 @@ import { Middleware } from "redux"; -import { SimulationInfo, SimulationInfoRaw } from "../../component/simulation"; +import { SimulationInfo } from "../../component/simulation"; import { Schema } from "../../utility/schema"; import { saveMiddleware } from "./save"; import { shadowBeamlineSortingMiddleware } from "./shadow/beamline"; diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index 8b9a34f414..08f617fd23 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -19,8 +19,9 @@ import { WaterfallLayout } from "./arrange/waterfall"; import { Histogram2dFromApi } from "./report/histogram2d"; import { ShadowBeamlineWatchpointReports } from "./shadow/beamlineWatchpointReports"; import { ShadowBeamlineLayout } from "./shadow/beamline"; -import { MadxBeamlineElementsLayout } from "./madx/beamlineElements"; +import { MadxAllBeamlineElementsLayout } from "./madx/allBeamlineElements"; import { MadxBeamlinesPickerLayout } from "./madx/beamlinesPicker"; +import { MadxBeamlineElementsLayout } from "./madx/beamlineElements"; // TODO rename to LayoutsWrapper @@ -49,8 +50,9 @@ class LayoutWrapper { waterfall: WaterfallLayout, shadowBeamlineWatchpointReports: ShadowBeamlineWatchpointReports, shadowBeamline: LayoutWithFormController(ShadowBeamlineLayout), - madxBeamlineElements: LayoutWithFormController(MadxBeamlineElementsLayout), - madxBeamlinesPicker: MadxBeamlinesPickerLayout + madxAllBeamlineElements: LayoutWithFormController(MadxAllBeamlineElementsLayout), + madxBeamlinesPicker: MadxBeamlinesPickerLayout, + madxBeamlineElements: LayoutWithFormController(MadxBeamlineElementsLayout) } constructor () { diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx new file mode 100644 index 0000000000..249a016469 --- /dev/null +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -0,0 +1,243 @@ +import React, { useContext, useState } from "react"; +import { FunctionComponent } from "react"; +import { Badge, Button, Modal, Tab, Table, Tabs } from "react-bootstrap"; +import { useDispatch, useStore } from "react-redux"; +import { formActionFunctions } from "../../component/reusable/form"; +import { Panel, ViewPanelActionButtons } from "../../component/reusable/panel"; +import { HandleFactoryWithOverrides } from "../../data/alias"; +import { CSchema } from "../../data/appwrapper"; +import { getValueSelector, newModelFromSchema, revertDataStructure, StoreTypes } from "../../data/data"; +import { Dependency } from "../../data/dependency"; +import { formStateFromModelState, FormStateHandleFactory } from "../../data/form"; +import { CHandleFactory } from "../../data/handle"; +import { useCoupledState } from "../../hook/coupling"; +import { ArrayFieldElement, ArrayFieldState } from "../../store/common"; +import { ModelState } from "../../store/models"; +import { Layout } from "../layout"; +import { LAYOUTS } from "../layouts"; + +export type TemplateSettings = { + type: string, + name: string, + modelName: string, + items: SchemaLayoutJson[] +} + +export type MadxAllBeamlineElementsConfig = { + elementsDependency: string, + templateGroups: { + name: string, + types: string[] + }[], + elementTemplates: TemplateSettings[] +} + +function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplete: (modelState: ModelState, model: string) => void, name: string, onHide: () => void }) { + let [layouts, _, updated] = useCoupledState(props.template, () => props.template.items.map((i, idx) => { + return LAYOUTS.getLayoutForSchema(i); + })) + + let schema = useContext(CSchema); + let store = useStore(); + let dispatch = useDispatch(); + let parentHandleFactory = useContext(CHandleFactory); + + let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [ + { + fake: props.template.modelName, + value: newModelFromSchema(schema.models[props.template.modelName], { name: props.name }), + onSave: (v) => props.onComplete(v, props.template.modelName) + } + ], parentHandleFactory); + + return ( + + + + {props.template.name} + + + {layouts.map((l, idx) => { + let Comp = l.component; + return ; + })} + + { + overridesHandleFactory.save(store.getState(), dispatch) + props.onHide(); + }} onCancel={props.onHide} canSave={overridesHandleFactory.isValid(store.getState())}/> + + + ) +} + +export class MadxAllBeamlineElementsLayout extends Layout { + constructor(config: MadxAllBeamlineElementsConfig) { + super(config); + } + + component: FunctionComponent<{ [key: string]: any; }> = (props) => { + let handleFactory = useContext(CHandleFactory) as FormStateHandleFactory; + handleFactory.useUpdates(MadxAllBeamlineElementsLayout); + let store = useStore(); + let dispatch = useDispatch(); + //let activeBeamlineId = handleFactory.createHandle(new Dependency(this.config.activeBeamlineDependency), StoreTypes.Models).hook().value; + let elementsHandle = handleFactory.createHandle(new Dependency(this.config.elementsDependency), StoreTypes.FormState).hook(); + let elementsValue = revertDataStructure(elementsHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; + + let [newElementModalShown, updateNewElementModalShown] = useState(false); + let [shownModalTemplate, updateShownModalTemplate] = useState(undefined); + let defaultGroup = this.config.templateGroups?.length > 0 ? this.config.templateGroups[0].name : undefined; + + let uniqueNameForType = (type: string) => { + let maxId = elementsValue.filter(e => e.model.charAt(0) === type.charAt(0)).reduce((prev: number, cur: ArrayFieldElement, idx) => { + let numberPart = (/.*?(\d*).*?/g).exec(cur.item.name as string)[1]; + return Math.max(prev, parseInt(numberPart.length > 0 ? numberPart : "0")) + }, 1); + return `${type.charAt(0)}${maxId + 1}` + } + + let getTemplateSettingsByType = (type: string) => { + let ret = this.config.elementTemplates.find(t => { + return t.type == type + }); + if(!ret) { + throw new Error(`could not find template settings for type=${type}, ${JSON.stringify(this.config.elementTemplates)}`) + } + return ret; + } + + let addBeamlineElement = (template: TemplateSettings, modelValue: ModelState, model: string) => { + console.log(`adding beamline element with type=${template.type}`, modelValue); + + let nv = [...(elementsHandle.value.value as any[])]; + let v = { + item: formStateFromModelState(modelValue), + model: model + } + console.log("nv before", nv); + console.log("V", v); + + nv.push(v) + + elementsHandle.write({ + ...elementsHandle.value, + value: nv + }, store.getState(), dispatch); + } + + let { cancel, submit } = formActionFunctions({ + formHandleFactory: handleFactory, + store, + dispatch + }); + + let actionButtons = handleFactory.isDirty() ? : undefined; + + return ( + <> + updateNewElementModalShown(false)}> + + New Beamline Element + + + + { + this.config.templateGroups?.map(tg => { + return ( + + { + ([...new Set(tg.types)].sort((a,b) => a.localeCompare(b))).map(t => { + let s = getTemplateSettingsByType(t); + return ( + + ) + }) + } + + ) + }) + } + + + + { + shownModalTemplate && ( + { + updateShownModalTemplate(undefined); + updateNewElementModalShown(false); + }} template={shownModalTemplate} onComplete={(mv, m) => addBeamlineElement(shownModalTemplate, mv, m)}/> + ) + } +
+ {actionButtons} +
+ +
+ + + + + + + + + + { + [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { + return ( + + + + + { + elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { + if(category === "COLLIMATOR") { + console.log(`${category}`, ev.item); + } + return ( + + + + + + + + + + ) + }) + } + + ) + + }) + } +
NameDescriptionLengthBend
+ + {category} + +
+
+ + {ev.item.name as string} + +
+
+ {/*??? TODO: garsuga: where does description come from*/} + + {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} + + {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} +
+ {actionButtons} +
+ + + ) + } +} diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index 649aabde53..63b53b1a54 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -1,243 +1,82 @@ -import React, { useContext, useState } from "react"; -import { FunctionComponent } from "react"; -import { Badge, Button, Modal, Tab, Table, Tabs } from "react-bootstrap"; -import { useDispatch, useStore } from "react-redux"; -import { formActionFunctions } from "../../component/reusable/form"; -import { Panel, ViewPanelActionButtons } from "../../component/reusable/panel"; -import { HandleFactoryWithOverrides } from "../../data/alias"; -import { CSchema } from "../../data/appwrapper"; -import { getValueSelector, newModelFromSchema, revertDataStructure, StoreTypes } from "../../data/data"; -import { Dependency } from "../../data/dependency"; -import { formStateFromModelState, FormStateHandleFactory } from "../../data/form"; +import { FunctionComponent, useContext, useState } from "react"; +import { getValueSelector, revertDataStructure, StoreTypes } from "../../data/data"; +import { FormStateHandleFactory } from "../../data/form"; import { CHandleFactory } from "../../data/handle"; -import { useCoupledState } from "../../hook/coupling"; +import { Layout } from "../layout"; +import { TemplateSettings } from "./allBeamlineElements"; +import { Dependency } from "../../data/dependency"; import { ArrayFieldElement, ArrayFieldState } from "../../store/common"; import { ModelState } from "../../store/models"; -import { Layout } from "../layout"; -import { LAYOUTS } from "../layouts"; - -type TemplateSettings = { - type: string, - name: string, - modelName: string, - items: SchemaLayoutJson[] -} +import React from "react"; +import { Badge } from "react-bootstrap"; +import { useCoupledState } from "../../hook/coupling"; +import { useDispatch, useStore } from "react-redux"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import * as Icon from "@fortawesome/free-solid-svg-icons"; +import * as IconRegular from "@fortawesome/free-regular-svg-icons"; -export type MadxBeamlineElementsConfig = { +export type MadxBeamlineElmenetsConfig = { + selectedBeamlineDependency: string, + beamlinesDependency: string, elementsDependency: string, - templateGroups: { - name: string, - types: string[] - }[], elementTemplates: TemplateSettings[] } -function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplete: (modelState: ModelState, model: string) => void, name: string, onHide: () => void }) { - let [layouts, _, updated] = useCoupledState(props.template, () => props.template.items.map((i, idx) => { - return LAYOUTS.getLayoutForSchema(i); - })) - - let schema = useContext(CSchema); - let store = useStore(); - let dispatch = useDispatch(); - let parentHandleFactory = useContext(CHandleFactory); - - let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [ - { - fake: props.template.modelName, - value: newModelFromSchema(schema.models[props.template.modelName], { name: props.name }), - onSave: (v) => props.onComplete(v, props.template.modelName) - } - ], parentHandleFactory); - - return ( - - - - {props.template.name} - - - {layouts.map((l, idx) => { - let Comp = l.component; - return ; - })} - - { - overridesHandleFactory.save(store.getState(), dispatch) - props.onHide(); - }} onCancel={props.onHide} canSave={overridesHandleFactory.isValid(store.getState())}/> - - - ) -} - -export class MadxBeamlineElementsLayout extends Layout { - constructor(config: MadxBeamlineElementsConfig) { - super(config); - } - +export class MadxBeamlineElementsLayout extends Layout { component: FunctionComponent<{ [key: string]: any; }> = (props) => { let handleFactory = useContext(CHandleFactory) as FormStateHandleFactory; - handleFactory.useUpdates(MadxBeamlineElementsLayout); let store = useStore(); let dispatch = useDispatch(); - //let activeBeamlineId = handleFactory.createHandle(new Dependency(this.config.activeBeamlineDependency), StoreTypes.Models).hook().value; - let elementsHandle = handleFactory.createHandle(new Dependency(this.config.elementsDependency), StoreTypes.FormState).hook(); - let elementsValue = revertDataStructure(elementsHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; - - let [newElementModalShown, updateNewElementModalShown] = useState(false); - let [shownModalTemplate, updateShownModalTemplate] = useState(undefined); - let defaultGroup = this.config.templateGroups?.length > 0 ? this.config.templateGroups[0].name : undefined; - - let uniqueNameForType = (type: string) => { - let maxId = elementsValue.filter(e => e.model.charAt(0) === type.charAt(0)).reduce((prev: number, cur: ArrayFieldElement, idx) => { - let numberPart = (/.*?(\d*).*?/g).exec(cur.item.name as string)[1]; - return Math.max(prev, parseInt(numberPart.length > 0 ? numberPart : "0")) - }, 1); - return `${type.charAt(0)}${maxId + 1}` - } + let isDirty = handleFactory.isDirty(); - let getTemplateSettingsByType = (type: string) => { - let ret = this.config.elementTemplates.find(t => { - return t.type == type - }); - if(!ret) { - throw new Error(`could not find template settings for type=${type}, ${JSON.stringify(this.config.elementTemplates)}`) + let selectedBeamlineHandle = handleFactory.createHandle(new Dependency(this.config.selectedBeamlineDependency), StoreTypes.Models).hook(); + // handles case where selected beamline changes and form is dirty + let _ = useCoupledState(selectedBeamlineHandle.value, () => { + if(isDirty) { + handleFactory.cancel(store.getState(), dispatch); } - return ret; - } - - let addBeamlineElement = (template: TemplateSettings, modelValue: ModelState, model: string) => { - console.log(`adding beamline element with type=${template.type}`, modelValue); - - let nv = [...(elementsHandle.value.value as any[])]; - let v = { - item: formStateFromModelState(modelValue), - model: model - } - console.log("nv before", nv); - console.log("V", v); + return selectedBeamlineHandle.value; + }) + let beamlinesHandle = handleFactory.createHandle(new Dependency(this.config.beamlinesDependency), StoreTypes.FormState).hook(); + let beamlinesValue = revertDataStructure(beamlinesHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; + let elementsHandle = handleFactory.createHandle(new Dependency(this.config.elementsDependency), StoreTypes.FormState).hook(); + let elementsValue = revertDataStructure(elementsHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; - nv.push(v) - - elementsHandle.write({ - ...elementsHandle.value, - value: nv - }, store.getState(), dispatch); + let _allItems = [...elementsValue, ...beamlinesValue]; + let findBeamlineOrElementById = (id: number): ArrayFieldElement => { + return _allItems.find(i => i.item.id === id || i.item._id === id); } + console.log("selectedBeamline", selectedBeamlineHandle.value); + console.log("elementsValue", elementsValue); - let { cancel, submit } = formActionFunctions({ - formHandleFactory: handleFactory, - store, - dispatch - }); + let currentBeamline = beamlinesValue.find(beam => beam.item.id === selectedBeamlineHandle.value).item; + console.log("currentBeamline", currentBeamline); + let beamlineElements = (currentBeamline.items as number[]).map(findBeamlineOrElementById) + console.log("beamlineElements", beamlineElements); - let actionButtons = handleFactory.isDirty() ? : undefined; + let [hoveredElement, updateHoveredElement] = useState(undefined); return ( - <> - updateNewElementModalShown(false)}> - - New Beamline Element - - - - { - this.config.templateGroups?.map(tg => { - return ( - - { - ([...new Set(tg.types)].sort((a,b) => a.localeCompare(b))).map(t => { - let s = getTemplateSettingsByType(t); - return ( - - ) - }) - } - - ) - }) - } - - - +
{ - shownModalTemplate && ( - { - updateShownModalTemplate(undefined); - updateNewElementModalShown(false); - }} template={shownModalTemplate} onComplete={(mv, m) => addBeamlineElement(shownModalTemplate, mv, m)}/> - ) + beamlineElements.map(e => { + let id = (e.item._id !== undefined ? e.item._id : e.item.id) as number; + let isHovered = id === hoveredElement; + return ( +
updateHoveredElement(id)} onMouseLeave={() => isHovered && updateHoveredElement(undefined)}> + + {`${e.item.name as string}`} + +
+
+ null}/> +
+
+
+ ) + }) } -
- {actionButtons} -
- -
- - - - - - - - - - { - [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { - return ( - - - - - { - elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { - if(category === "COLLIMATOR") { - console.log(`${category}`, ev.item); - } - return ( - - - - - - - - - - ) - }) - } - - ) - - }) - } -
NameDescriptionLengthBend
- - {category} - -
-
- - {ev.item.name as string} - -
-
- {/*??? TODO: garsuga: where does description come from*/} - - {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} - - {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} -
- {actionButtons} -
- - +
) } } diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 3b45817aa5..330cb4adc4 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -6519,13 +6519,1084 @@ ] } }, + { + "layout": "panel", + "config": { + "title": "Beamline Editor - $(simulation.activeBeamlineId)", + "basic": [ + { + "layout": "madxBeamlineElements", + "config": { + "elementsDependency": "elements.elements", + "beamlinesDependency": "lattice.beamlines", + "selectedBeamlineDependency": "simulation.activeBeamlineId", + "elementTemplates": [ + { + "type": "BEAMBEAM", + "name": "BEAMBEAM", + "modelName": "BEAMBEAM", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "BEAMBEAM.name", + "BEAMBEAM.sigx", + "BEAMBEAM.sigy", + "BEAMBEAM.xma", + "BEAMBEAM.yma", + "BEAMBEAM.charge", + "BEAMBEAM.bbshape", + "BEAMBEAM.width", + "BEAMBEAM.bbdir", + "BEAMBEAM.apertype", + "BEAMBEAM.aperture", + "BEAMBEAM.aper_offset", + "BEAMBEAM.aper_tol" + ] + } + } + ] + }, + { + "type": "CHANGEREF", + "name": "CHANGEREF", + "modelName": "CHANGEREF", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CHANGEREF.name", + "CHANGEREF.patch_ang", + "CHANGEREF.patch_trans", + "CHANGEREF.apertype", + "CHANGEREF.aperture", + "CHANGEREF.aper_offset", + "CHANGEREF.aper_tol" + ] + } + } + ] + }, + { + "type": "COLLIMATOR", + "name": "COLLIMATOR", + "modelName": "COLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "COLLIMATOR.name", + "COLLIMATOR.l", + "COLLIMATOR.apertype", + "COLLIMATOR.aperture", + "COLLIMATOR.aper_offset", + "COLLIMATOR.aper_tol" + ] + } + } + ] + }, + { + "type": "CRABCAVITY", + "name": "CRABCAVITY", + "modelName": "CRABCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "CRABCAVITY.name", + "CRABCAVITY.l", + "CRABCAVITY.volt", + "CRABCAVITY.lag", + "CRABCAVITY.freq", + "CRABCAVITY.rv1", + "CRABCAVITY.rv2", + "CRABCAVITY.rv3", + "CRABCAVITY.rv4", + "CRABCAVITY.rph1", + "CRABCAVITY.rph2", + "CRABCAVITY.lagf", + "CRABCAVITY.apertype", + "CRABCAVITY.aperture", + "CRABCAVITY.aper_offset", + "CRABCAVITY.aper_tol" + ] + } + } + ] + }, + { + "type": "DIPEDGE", + "name": "DIPEDGE", + "modelName": "DIPEDGE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DIPEDGE.name", + "DIPEDGE.h", + "DIPEDGE.e1", + "DIPEDGE.fint", + "DIPEDGE.hgap", + "DIPEDGE.tilt", + "DIPEDGE.apertype", + "DIPEDGE.aperture", + "DIPEDGE.aper_offset", + "DIPEDGE.aper_tol" + ] + } + } + ] + }, + { + "type": "DRIFT", + "name": "DRIFT", + "modelName": "DRIFT", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "DRIFT.name", + "DRIFT.l" + ] + } + } + ] + }, + { + "type": "ECOLLIMATOR", + "name": "ECOLLIMATOR", + "modelName": "ECOLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "ECOLLIMATOR.name", + "ECOLLIMATOR.l", + "ECOLLIMATOR.xsize", + "ECOLLIMATOR.ysize", + "ECOLLIMATOR.apertype", + "ECOLLIMATOR.aperture", + "ECOLLIMATOR.aper_offset", + "ECOLLIMATOR.aper_tol" + ] + } + } + ] + }, + { + "type": "HACDIPOLE", + "name": "HACDIPOLE", + "modelName": "HACDIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HACDIPOLE.name", + "HACDIPOLE.l", + "HACDIPOLE.volt", + "HACDIPOLE.freq", + "HACDIPOLE.lag", + "HACDIPOLE.ramp1", + "HACDIPOLE.ramp2", + "HACDIPOLE.ramp3", + "HACDIPOLE.ramp4", + "HACDIPOLE.apertype", + "HACDIPOLE.aperture", + "HACDIPOLE.aper_offset", + "HACDIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "HKICKER", + "name": "HKICKER", + "modelName": "HKICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HKICKER.name", + "HKICKER.l", + "HKICKER.kick", + "HKICKER.tilt", + "HKICKER.apertype", + "HKICKER.aperture", + "HKICKER.aper_offset", + "HKICKER.aper_tol" + ] + } + } + ] + }, + { + "type": "HMONITOR", + "name": "HMONITOR", + "modelName": "HMONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "HMONITOR.name", + "HMONITOR.l", + "HMONITOR.apertype", + "HMONITOR.aperture", + "HMONITOR.aper_offset", + "HMONITOR.aper_tol" + ] + } + } + ] + }, + { + "type": "INSTRUMENT", + "name": "INSTRUMENT", + "modelName": "INSTRUMENT", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "INSTRUMENT.name", + "INSTRUMENT.l", + "INSTRUMENT.apertype", + "INSTRUMENT.aperture", + "INSTRUMENT.aper_offset", + "INSTRUMENT.aper_tol" + ] + } + } + ] + }, + { + "type": "KICKER", + "name": "KICKER", + "modelName": "KICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "KICKER.name", + "KICKER.l", + "KICKER.hkick", + "KICKER.vkick", + "KICKER.tilt", + "KICKER.apertype", + "KICKER.aperture", + "KICKER.aper_offset", + "KICKER.aper_tol" + ] + } + } + ] + }, + { + "type": "MARKER", + "name": "MARKER", + "modelName": "MARKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MARKER.name", + "MARKER.apertype", + "MARKER.aperture", + "MARKER.aper_offset", + "MARKER.aper_tol" + ] + } + } + ] + }, + { + "type": "MATRIX", + "name": "MATRIX", + "modelName": "MATRIX", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MATRIX.name", + "MATRIX.l", + "MATRIX.kick1", + "MATRIX.kick6", + "MATRIX.rm11", + "MATRIX.rm66", + "MATRIX.tm111", + "MATRIX.tm666", + "MATRIX.kick2", + "MATRIX.kick3", + "MATRIX.kick4", + "MATRIX.kick5", + "MATRIX.rm12", + "MATRIX.rm13", + "MATRIX.rm14", + "MATRIX.rm15", + "MATRIX.rm16", + "MATRIX.rm21", + "MATRIX.rm22", + "MATRIX.rm23", + "MATRIX.rm24", + "MATRIX.rm25", + "MATRIX.rm26", + "MATRIX.rm31", + "MATRIX.rm32", + "MATRIX.rm33", + "MATRIX.rm34", + "MATRIX.rm35", + "MATRIX.rm36", + "MATRIX.rm41", + "MATRIX.rm42", + "MATRIX.rm43", + "MATRIX.rm44", + "MATRIX.rm45", + "MATRIX.rm46", + "MATRIX.rm51", + "MATRIX.rm52", + "MATRIX.rm53", + "MATRIX.rm54", + "MATRIX.rm55", + "MATRIX.rm56", + "MATRIX.rm61", + "MATRIX.rm62", + "MATRIX.rm63", + "MATRIX.rm64", + "MATRIX.rm65", + "MATRIX.tm112", + "MATRIX.tm113", + "MATRIX.tm114", + "MATRIX.tm115", + "MATRIX.tm116", + "MATRIX.tm121", + "MATRIX.tm122", + "MATRIX.tm123", + "MATRIX.tm124", + "MATRIX.tm125", + "MATRIX.tm126", + "MATRIX.tm131", + "MATRIX.tm132", + "MATRIX.tm133", + "MATRIX.tm134", + "MATRIX.tm135", + "MATRIX.tm136", + "MATRIX.tm141", + "MATRIX.tm142", + "MATRIX.tm143", + "MATRIX.tm144", + "MATRIX.tm145", + "MATRIX.tm146", + "MATRIX.tm151", + "MATRIX.tm152", + "MATRIX.tm153", + "MATRIX.tm154", + "MATRIX.tm155", + "MATRIX.tm156", + "MATRIX.tm161", + "MATRIX.tm162", + "MATRIX.tm163", + "MATRIX.tm164", + "MATRIX.tm165", + "MATRIX.tm166", + "MATRIX.tm211", + "MATRIX.tm212", + "MATRIX.tm213", + "MATRIX.tm214", + "MATRIX.tm215", + "MATRIX.tm216", + "MATRIX.tm221", + "MATRIX.tm222", + "MATRIX.tm223", + "MATRIX.tm224", + "MATRIX.tm225", + "MATRIX.tm226", + "MATRIX.tm231", + "MATRIX.tm232", + "MATRIX.tm233", + "MATRIX.tm234", + "MATRIX.tm235", + "MATRIX.tm236", + "MATRIX.tm241", + "MATRIX.tm242", + "MATRIX.tm243", + "MATRIX.tm244", + "MATRIX.tm245", + "MATRIX.tm246", + "MATRIX.tm251", + "MATRIX.tm252", + "MATRIX.tm253", + "MATRIX.tm254", + "MATRIX.tm255", + "MATRIX.tm256", + "MATRIX.tm261", + "MATRIX.tm262", + "MATRIX.tm263", + "MATRIX.tm264", + "MATRIX.tm265", + "MATRIX.tm266", + "MATRIX.tm311", + "MATRIX.tm312", + "MATRIX.tm313", + "MATRIX.tm314", + "MATRIX.tm315", + "MATRIX.tm316", + "MATRIX.tm321", + "MATRIX.tm322", + "MATRIX.tm323", + "MATRIX.tm324", + "MATRIX.tm325", + "MATRIX.tm326", + "MATRIX.tm331", + "MATRIX.tm332", + "MATRIX.tm333", + "MATRIX.tm334", + "MATRIX.tm335", + "MATRIX.tm336", + "MATRIX.tm341", + "MATRIX.tm342", + "MATRIX.tm343", + "MATRIX.tm344", + "MATRIX.tm345", + "MATRIX.tm346", + "MATRIX.tm351", + "MATRIX.tm352", + "MATRIX.tm353", + "MATRIX.tm354", + "MATRIX.tm355", + "MATRIX.tm356", + "MATRIX.tm361", + "MATRIX.tm362", + "MATRIX.tm363", + "MATRIX.tm364", + "MATRIX.tm365", + "MATRIX.tm366", + "MATRIX.tm411", + "MATRIX.tm412", + "MATRIX.tm413", + "MATRIX.tm414", + "MATRIX.tm415", + "MATRIX.tm416", + "MATRIX.tm421", + "MATRIX.tm422", + "MATRIX.tm423", + "MATRIX.tm424", + "MATRIX.tm425", + "MATRIX.tm426", + "MATRIX.tm431", + "MATRIX.tm432", + "MATRIX.tm433", + "MATRIX.tm434", + "MATRIX.tm435", + "MATRIX.tm436", + "MATRIX.tm441", + "MATRIX.tm442", + "MATRIX.tm443", + "MATRIX.tm444", + "MATRIX.tm445", + "MATRIX.tm446", + "MATRIX.tm451", + "MATRIX.tm452", + "MATRIX.tm453", + "MATRIX.tm454", + "MATRIX.tm455", + "MATRIX.tm456", + "MATRIX.tm461", + "MATRIX.tm462", + "MATRIX.tm463", + "MATRIX.tm464", + "MATRIX.tm465", + "MATRIX.tm466", + "MATRIX.tm511", + "MATRIX.tm512", + "MATRIX.tm513", + "MATRIX.tm514", + "MATRIX.tm515", + "MATRIX.tm516", + "MATRIX.tm521", + "MATRIX.tm522", + "MATRIX.tm523", + "MATRIX.tm524", + "MATRIX.tm525", + "MATRIX.tm526", + "MATRIX.tm531", + "MATRIX.tm532", + "MATRIX.tm533", + "MATRIX.tm534", + "MATRIX.tm535", + "MATRIX.tm536", + "MATRIX.tm541", + "MATRIX.tm542", + "MATRIX.tm543", + "MATRIX.tm544", + "MATRIX.tm545", + "MATRIX.tm546", + "MATRIX.tm551", + "MATRIX.tm552", + "MATRIX.tm553", + "MATRIX.tm554", + "MATRIX.tm555", + "MATRIX.tm556", + "MATRIX.tm561", + "MATRIX.tm562", + "MATRIX.tm563", + "MATRIX.tm564", + "MATRIX.tm565", + "MATRIX.tm566", + "MATRIX.tm611", + "MATRIX.tm612", + "MATRIX.tm613", + "MATRIX.tm614", + "MATRIX.tm615", + "MATRIX.tm616", + "MATRIX.tm621", + "MATRIX.tm622", + "MATRIX.tm623", + "MATRIX.tm624", + "MATRIX.tm625", + "MATRIX.tm626", + "MATRIX.tm631", + "MATRIX.tm632", + "MATRIX.tm633", + "MATRIX.tm634", + "MATRIX.tm635", + "MATRIX.tm636", + "MATRIX.tm641", + "MATRIX.tm642", + "MATRIX.tm643", + "MATRIX.tm644", + "MATRIX.tm645", + "MATRIX.tm646", + "MATRIX.tm651", + "MATRIX.tm652", + "MATRIX.tm653", + "MATRIX.tm654", + "MATRIX.tm655", + "MATRIX.tm656", + "MATRIX.tm661", + "MATRIX.tm662", + "MATRIX.tm663", + "MATRIX.tm664", + "MATRIX.tm665" + ] + } + } + ] + }, + { + "type": "MONITOR", + "name": "MONITOR", + "modelName": "MONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MONITOR.name", + "MONITOR.l", + "MONITOR.apertype", + "MONITOR.aperture", + "MONITOR.aper_offset", + "MONITOR.aper_tol" + ] + } + } + ] + }, + { + "type": "MULTIPOLE", + "name": "MULTIPOLE", + "modelName": "MULTIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "MULTIPOLE.name", + "MULTIPOLE.lrad", + "MULTIPOLE.tilt", + "MULTIPOLE.knl", + "MULTIPOLE.ksl", + "MULTIPOLE.apertype", + "MULTIPOLE.aperture", + "MULTIPOLE.aper_offset", + "MULTIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "NLLENS", + "name": "NLLENS", + "modelName": "NLLENS", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "NLLENS.name", + "NLLENS.knll", + "NLLENS.cnll", + "NLLENS.apertype", + "NLLENS.aperture", + "NLLENS.aper_offset", + "NLLENS.aper_tol" + ] + } + } + ] + }, + { + "type": "OCTUPOLE", + "name": "OCTUPOLE", + "modelName": "OCTUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "OCTUPOLE.name", + "OCTUPOLE.l", + "OCTUPOLE.k3", + "OCTUPOLE.k3s", + "OCTUPOLE.tilt", + "OCTUPOLE.apertype", + "OCTUPOLE.aperture", + "OCTUPOLE.aper_offset", + "OCTUPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "PLACEHOLDER", + "name": "PLACEHOLDER", + "modelName": "PLACEHOLDER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "PLACEHOLDER.name", + "PLACEHOLDER.l", + "PLACEHOLDER.apertype", + "PLACEHOLDER.aperture", + "PLACEHOLDER.aper_offset", + "PLACEHOLDER.aper_tol" + ] + } + } + ] + }, + { + "type": "QUADRUPOLE", + "name": "QUADRUPOLE", + "modelName": "QUADRUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "QUADRUPOLE.name", + "QUADRUPOLE.l", + "QUADRUPOLE.k1", + "QUADRUPOLE.k1s", + "QUADRUPOLE.tilt", + "QUADRUPOLE.thick", + "QUADRUPOLE.apertype", + "QUADRUPOLE.aperture", + "QUADRUPOLE.aper_offset", + "QUADRUPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "RBEND", + "name": "RBEND", + "modelName": "RBEND", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RBEND.name", + "RBEND.l", + "RBEND.angle", + "RBEND.tilt", + "RBEND.k1", + "RBEND.k2", + "RBEND.e1", + "RBEND.e2", + "RBEND.fint", + "RBEND.fintx", + "RBEND.hgap", + "RBEND.h1", + "RBEND.h2", + "RBEND.add_angle", + "RBEND.thick", + "RBEND.apertype", + "RBEND.aperture", + "RBEND.aper_offset", + "RBEND.aper_tol" + ] + } + } + ] + }, + { + "type": "RCOLLIMATOR", + "name": "RCOLLIMATOR", + "modelName": "RCOLLIMATOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RCOLLIMATOR.name", + "RCOLLIMATOR.l", + "RCOLLIMATOR.xsize", + "RCOLLIMATOR.ysize", + "RCOLLIMATOR.apertype", + "RCOLLIMATOR.aperture", + "RCOLLIMATOR.aper_offset", + "RCOLLIMATOR.aper_tol" + ] + } + } + ] + }, + { + "type": "RFCAVITY", + "name": "RFCAVITY", + "modelName": "RFCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFCAVITY.name", + "RFCAVITY.l", + "RFCAVITY.volt", + "RFCAVITY.lag", + "RFCAVITY.harmon", + "RFCAVITY.freq", + "RFCAVITY.apertype", + "RFCAVITY.aperture", + "RFCAVITY.aper_offset", + "RFCAVITY.aper_tol" + ] + } + } + ] + }, + { + "type": "RFMULTIPOLE", + "name": "RFMULTIPOLE", + "modelName": "RFMULTIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "RFMULTIPOLE.name", + "RFMULTIPOLE.volt", + "RFMULTIPOLE.lag", + "RFMULTIPOLE.harmon", + "RFMULTIPOLE.freq", + "RFMULTIPOLE.lrad", + "RFMULTIPOLE.tilt", + "RFMULTIPOLE.knl", + "RFMULTIPOLE.ksl", + "RFMULTIPOLE.pnl", + "RFMULTIPOLE.psl", + "RFMULTIPOLE.apertype", + "RFMULTIPOLE.aperture", + "RFMULTIPOLE.aper_offset", + "RFMULTIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "SBEND", + "name": "SBEND", + "modelName": "SBEND", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SBEND.name", + "SBEND.l", + "SBEND.angle", + "SBEND.k1", + "SBEND.k2", + "SBEND.e1", + "SBEND.e2", + "SBEND.tilt", + "SBEND.h1", + "SBEND.h2", + "SBEND.hgap", + "SBEND.fint", + "SBEND.fintx", + "SBEND.thick", + "SBEND.apertype", + "SBEND.aperture", + "SBEND.aper_offset", + "SBEND.aper_tol" + ] + } + } + ] + }, + { + "type": "SEXTUPOLE", + "name": "SEXTUPOLE", + "modelName": "SEXTUPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SEXTUPOLE.name", + "SEXTUPOLE.l", + "SEXTUPOLE.k2", + "SEXTUPOLE.k2s", + "SEXTUPOLE.tilt", + "SEXTUPOLE.apertype", + "SEXTUPOLE.aperture", + "SEXTUPOLE.aper_offset", + "SEXTUPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "SOLENOID", + "name": "SOLENOID", + "modelName": "SOLENOID", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SOLENOID.name", + "SOLENOID.l", + "SOLENOID.ks", + "SOLENOID.ksi", + "SOLENOID.apertype", + "SOLENOID.aperture", + "SOLENOID.aper_offset", + "SOLENOID.aper_tol" + ] + } + } + ] + }, + { + "type": "SROTATION", + "name": "SROTATION", + "modelName": "SROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "SROTATION.name", + "SROTATION.angle", + "SROTATION.apertype", + "SROTATION.aperture", + "SROTATION.aper_offset", + "SROTATION.aper_tol" + ] + } + } + ] + }, + { + "type": "TRANSLATION", + "name": "TRANSLATION", + "modelName": "TRANSLATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TRANSLATION.name", + "TRANSLATION.dx", + "TRANSLATION.dy", + "TRANSLATION.ds" + ] + } + } + ] + }, + { + "type": "TWCAVITY", + "name": "TWCAVITY", + "modelName": "TWCAVITY", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "TWCAVITY.name", + "TWCAVITY.l", + "TWCAVITY.volt", + "TWCAVITY.freq", + "TWCAVITY.lag", + "TWCAVITY.psi", + "TWCAVITY.delta_lag", + "TWCAVITY.apertype", + "TWCAVITY.aperture", + "TWCAVITY.aper_offset", + "TWCAVITY.aper_tol" + ] + } + } + ] + }, + { + "type": "VACDIPOLE", + "name": "VACDIPOLE", + "modelName": "VACDIPOLE", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VACDIPOLE.name", + "VACDIPOLE.l", + "VACDIPOLE.volt", + "VACDIPOLE.freq", + "VACDIPOLE.lag", + "VACDIPOLE.ramp1", + "VACDIPOLE.ramp2", + "VACDIPOLE.ramp3", + "VACDIPOLE.ramp4", + "VACDIPOLE.apertype", + "VACDIPOLE.aperture", + "VACDIPOLE.aper_offset", + "VACDIPOLE.aper_tol" + ] + } + } + ] + }, + { + "type": "VKICKER", + "name": "VKICKER", + "modelName": "VKICKER", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VKICKER.name", + "VKICKER.l", + "VKICKER.kick", + "VKICKER.tilt", + "VKICKER.apertype", + "VKICKER.aperture", + "VKICKER.aper_offset", + "VKICKER.aper_tol" + ] + } + } + ] + }, + { + "type": "VMONITOR", + "name": "VMONITOR", + "modelName": "VMONITOR", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "VMONITOR.name", + "VMONITOR.l", + "VMONITOR.apertype", + "VMONITOR.aperture", + "VMONITOR.aper_offset", + "VMONITOR.aper_tol" + ] + } + } + ] + }, + { + "type": "XROTATION", + "name": "XROTATION", + "modelName": "XROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "XROTATION.name", + "XROTATION.angle", + "XROTATION.apertype", + "XROTATION.aperture", + "XROTATION.aper_offset", + "XROTATION.aper_tol" + ] + } + } + ] + }, + { + "type": "YROTATION", + "name": "YROTATION", + "modelName": "YROTATION", + "items": [ + { + "layout": "fieldList", + "config": { + "fields": [ + "YROTATION.name", + "YROTATION.angle", + "YROTATION.apertype", + "YROTATION.aperture", + "YROTATION.aper_offset", + "YROTATION.aper_tol" + ] + } + } + ] + } + ] + } + } + ] + } + }, { "layout": "panel", "config": { "title": "Beamline Elements", "basic": [ { - "layout": "madxBeamlineElements", + "layout": "madxAllBeamlineElements", "config": { "elementsDependency": "elements.elements", "templateGroups": [ @@ -7602,7 +8673,6 @@ ] } } - ] } } From 442ceb4a416f5dcc3b92d24b7afeaf210575ec44 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 11 May 2023 20:05:53 +0000 Subject: [PATCH 44/68] wip --- react/src/component/reusable/hover.tsx | 28 ++ react/src/data/alias.ts | 109 +++++++- react/src/data/form.ts | 6 +- react/src/data/handle.ts | 57 ++-- react/src/data/report.ts | 4 +- react/src/layout/layouts.ts | 4 +- .../src/layout/madx/allBeamlineElements.scss | 0 react/src/layout/madx/allBeamlineElements.tsx | 243 ++++++++++++------ react/src/layout/madx/beamlineElements.tsx | 82 ++++-- react/src/layout/madx/beamlineReports.tsx | 180 +++++++++++++ react/src/layout/madx/beamlines.scss | 24 ++ react/src/layout/madx/beamlinesPicker.tsx | 82 +++--- react/src/layout/report.tsx | 18 +- .../static/react-json/madx-schema.json | 189 +++++++++----- sirepo/template/lattice.py | 36 ++- sirepo/template/madx.py | 4 +- 16 files changed, 799 insertions(+), 267 deletions(-) create mode 100644 react/src/component/reusable/hover.tsx create mode 100644 react/src/layout/madx/allBeamlineElements.scss create mode 100644 react/src/layout/madx/beamlineReports.tsx create mode 100644 react/src/layout/madx/beamlines.scss diff --git a/react/src/component/reusable/hover.tsx b/react/src/component/reusable/hover.tsx new file mode 100644 index 0000000000..996f1d9d9c --- /dev/null +++ b/react/src/component/reusable/hover.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { useState } from "react"; + +export type Hover = { + aquireHover: (id: any) => void; + releaseHover: (id: any) => void; + checkHover: (id: any) => boolean +} + +export function HoverController(props: { + children: (hover: Hover) => React.ReactNode +}) { + let [hoveredId, updateHoveredId] = useState(undefined); + + let hover: Hover = { + aquireHover: (id: any) => updateHoveredId(id), + releaseHover: (id: any) => (hoveredId === id ? updateHoveredId(undefined) : undefined), + checkHover: (id: any) => hoveredId === id + } + + return ( + <> + { + props.children && props.children(hover) + } + + ) +} diff --git a/react/src/data/alias.ts b/react/src/data/alias.ts index 5e6ac095e1..f20356dc11 100644 --- a/react/src/data/alias.ts +++ b/react/src/data/alias.ts @@ -1,9 +1,9 @@ import { Dispatch, AnyAction } from "redux"; -import { ArrayFieldState, StoreState } from "../store/common"; +import { ArrayFieldElement, ArrayFieldState, StoreState } from "../store/common"; import { Schema } from "../utility/schema"; import { expandDataStructure, getValueSelector, revertDataStructure, StoreType, StoreTypes, ValueSelectors } from "./data"; import { Dependency } from "./dependency"; -import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; +import { DataHandle, EmptyDataHandle, EmptyModelHandle, HandleFactory, ModelHandle } from "./handle"; import cloneDeep from 'lodash/cloneDeep'; import { ModelState } from "../store/models"; import { FormModelState } from "../store/formState"; @@ -11,12 +11,14 @@ import { callNextParentFunction, FormActionFunc, formStateFromSingleValue, initi import { mapProperties } from "../utility/object"; import { useState } from "react"; +export type AliasDataLocation = { + modelName: string, + fieldName: string, + index: number +} + export type ArrayAliases = { - realDataLocation: { - modelName: string, - fieldName: string, - index: number - }, + realDataLocation: AliasDataLocation, realSchemaName: string, fake: string }[] @@ -26,17 +28,30 @@ export class HandleFactoryWithArrayAliases extends HandleFactory { super(schema, parent); } + private emptyAliasedHandle = (location: AliasDataLocation, type: StoreType): EmptyDataHandle => { + return this.parent.createHandle(new Dependency(`${location.modelName}.${location.fieldName}`), type); + } + + private getArrayElementFromParentHandle = (dh: DataHandle, index: number, type: StoreType): ArrayFieldElement => { + let mv = getValueSelector(type)(dh.value)[index]; + if(!mv) { + console.error(`could not find index=${index}`); + console.error(`was looking in`, getValueSelector(type)(dh.value)) + } + return mv; + } + createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle> => { + console.log(`alias handle factory creating handle for ${dependency.getDependencyString()}`); let alias = this.aliases.find(a => a.fake === dependency.modelName); + console.log(`alias=${alias}`); + console.log(`aliases`, this.aliases); + let getAE = this.getArrayElementFromParentHandle; if(alias !== undefined) { - let edh = this.parent.createHandle(new Dependency(`${alias.realDataLocation.modelName}.${alias.realDataLocation.fieldName}`), type); + let edh = this.emptyAliasedHandle(alias.realDataLocation, type); return new (class implements EmptyDataHandle { private createDummyHandle(dh: DataHandle): DataHandle { - let mv = getValueSelector(type)(dh.value)[alias.realDataLocation.index]; - if(!mv) { - console.error(`could not find index=${alias.realDataLocation.index}`); - console.error(`was looking in`, getValueSelector(type)(dh.value)) - } + let mv = getAE(dh, alias.realDataLocation.index, type); let fv = mv.item[dependency.fieldName]; return new (class extends DataHandle { write(value: F, state: StoreState, dispatch: Dispatch) { @@ -58,6 +73,58 @@ export class HandleFactoryWithArrayAliases extends HandleFactory { } return this.parent.createHandle(dependency, type); } + + createModelHandle(modelName: string, type: StoreType): EmptyModelHandle> { + let alias = this.aliases.find(a => a.fake === modelName); + if(alias === undefined) { + return this.parent.createModelHandle(modelName, type); + } + + let edh = this.emptyAliasedHandle(alias.realDataLocation, type); + + return { + initialize: (state) => { + let dh = edh.initialize(state); + return new ModelHandle(this.getArrayElementFromParentHandle(dh, alias.realDataLocation.index, type).item); + }, + hook: () => { + let dh = edh.hook(); + return new ModelHandle(this.getArrayElementFromParentHandle(dh, alias.realDataLocation.index, type).item); + } + } + } +} + +export type HandleFactorySimpleAliases = { + real: string, + fake: string +}[] + +export class HandleFactoryWithSimpleAliases extends HandleFactory { + constructor(schema: Schema, private aliases: HandleFactorySimpleAliases, parent: HandleFactory) { + super(schema, parent); + } + + private findAlias(name: string) { + return this.aliases.find(a => a.fake === name); + } + + createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle> { + let alias = this.findAlias(dependency.modelName); + if(alias) { + return this.parent.createHandle(new Dependency(`${alias.real}.${dependency.fieldName}`), type); + } + return this.parent.createHandle(dependency, type); + } + + createModelHandle(modelName: string, type: StoreType): EmptyModelHandle> { + let alias = this.findAlias(modelName); + if(alias) { + return this.parent.createModelHandle(alias.real, type); + } + return this.parent.createModelHandle(modelName, type); + } + } export type HandleFactoryOverrides = { @@ -153,4 +220,20 @@ export class HandleFactoryWithOverrides extends HandleFactory { return this.parent.createHandle(dependency, type); } + + createModelHandle(modelName: string, type: StoreType): EmptyModelHandle> { + let override = this.overrides.find(a => a.fake === modelName); + if(override === undefined) { + return this.parent.createModelHandle(modelName, type); + } + let mv = (type === StoreTypes.Models ? override.value : override.formValue) as M; + return { + initialize: (state: any) => { + return new ModelHandle(mv); + }, + hook: () => { + return new ModelHandle(mv); + } + } + } } diff --git a/react/src/data/form.ts b/react/src/data/form.ts index 2332ebb008..32bd5281c9 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -7,7 +7,7 @@ import { Dictionary, mapProperties } from "../utility/object"; import { Schema } from "../utility/schema"; import { StoreType, StoreTypes, expandDataStructure, revertDataStructure, getValueSelector } from "./data"; import { Dependency } from "./dependency"; -import { DataHandle, EmptyDataHandle, HandleFactory } from "./handle"; +import { DataHandle, EmptyDataHandle, EmptyModelHandle, HandleFactory, ModelHandle } from "./handle"; export type FormActionFunc = (state: any, dispatch: Dispatch) => void type FormSelectorFunc = (state: any) => V @@ -148,4 +148,8 @@ export class FormStateHandleFactory extends HandleFactory { } return edh; } + + createModelHandle(modelName: string, type: StoreType): EmptyModelHandle> { + return this.parent.createModelHandle(modelName, type); + } } diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 722b128fc5..42f90bba31 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -29,16 +29,33 @@ export interface EmptyDataHandle = DataHandle { + constructor(initialModelValue: M) { + this.value = initialModelValue; + } + + readonly value: M +} +export interface EmptyModelHandle = ModelHandle> { + initialize(state: any): D; + hook(): D +} + export type SelectorUser = (selector: (state: any) => M) => M; export abstract class HandleFactory { constructor(protected schema: Schema, public parent?: HandleFactory) {} abstract createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle; + abstract createModelHandle(modelName: string, type: StoreType): EmptyModelHandle; } export class BaseHandleFactory extends HandleFactory { - createHandle(dependency: Dependency, type: StoreType): EmptyDataHandle { - let ms = getModelReadSelector(type)(dependency.modelName); + private modelSelector = (modelName: string, type: StoreType): (state: any) => M => { + return getModelReadSelector(type)(modelName); + } + + createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle => { + let ms = this.modelSelector(dependency.modelName, type); let mac = getModelWriteActionCreator(type); let cdh = (value: F): DataHandle => { return new (class extends DataHandle { @@ -54,9 +71,24 @@ export class BaseHandleFactory extends HandleFactory { return cdh(ms(state)[dependency.fieldName]); }, hook: () => { - let mv = useSelector(ms); - //console.log("dependency", dependency.getDependencyString(), mv); - return cdh(mv[dependency.fieldName]); + return cdh(useSelector(ms)[dependency.fieldName]); + } + } + } + + createModelHandle = (modelName: string, type: StoreType): EmptyModelHandle> => { + let ms = this.modelSelector(modelName, type); + + let cmh = (value: M): ModelHandle => { + return new ModelHandle(value); + } + + return { + initialize: (state: any) => { + return cmh(ms(state)); + }, + hook: () => { + return cmh(useSelector(ms)); } } } @@ -112,16 +144,7 @@ export class DependencyReader { } -export function useModelValue(modelName: string, type: StoreType): M { +/*export function useModelValue(modelName: string, type: StoreType): M { let ms = getModelReadSelector(type); - return useSelector(ms(modelName)) - - /*return Object.fromEntries(new DependencyReader([new Dependency(`${modelName}.*`)], StoreTypes.Models, schema).hook().map(pair => { - return [ - pair.dependency.fieldName, - pair.value - ] - }));*/ - - -} + return useSelector(ms(modelName); +}*/ diff --git a/react/src/data/report.ts b/react/src/data/report.ts index 725e1d242e..617978e8bd 100644 --- a/react/src/data/report.ts +++ b/react/src/data/report.ts @@ -47,7 +47,7 @@ export class ReportEventManager { } } - private callListenerWithData = (listener: ReportEventSubscriber, simulationData: ResponseHasState) => { + protected callListenerWithData = (listener: ReportEventSubscriber, simulationData: ResponseHasState) => { listener.onReportData && listener.onReportData(simulationData); if(simulationData.state === 'completed') { listener.onComplete && listener.onComplete() @@ -58,7 +58,7 @@ export class ReportEventManager { this.reportEventListeners = mapProperties(this.reportEventListeners, (_, listeners) => Object.fromEntries(Object.entries(listeners).filter(([k,]) => k !== key))); } - getListenersForReport: (report: string) => ReportEventSubscriber[] = (report: string) => { + private getListenersForReport: (report: string) => ReportEventSubscriber[] = (report: string) => { return Object.entries(this.reportEventListeners[report] || {}).map(([, listener]) => listener); } diff --git a/react/src/layout/layouts.ts b/react/src/layout/layouts.ts index 08f617fd23..21568b0c12 100644 --- a/react/src/layout/layouts.ts +++ b/react/src/layout/layouts.ts @@ -22,6 +22,7 @@ import { ShadowBeamlineLayout } from "./shadow/beamline"; import { MadxAllBeamlineElementsLayout } from "./madx/allBeamlineElements"; import { MadxBeamlinesPickerLayout } from "./madx/beamlinesPicker"; import { MadxBeamlineElementsLayout } from "./madx/beamlineElements"; +import { MadxBeamlineReportsLayout } from "./madx/beamlineReports"; // TODO rename to LayoutsWrapper @@ -52,7 +53,8 @@ class LayoutWrapper { shadowBeamline: LayoutWithFormController(ShadowBeamlineLayout), madxAllBeamlineElements: LayoutWithFormController(MadxAllBeamlineElementsLayout), madxBeamlinesPicker: MadxBeamlinesPickerLayout, - madxBeamlineElements: LayoutWithFormController(MadxBeamlineElementsLayout) + madxBeamlineElements: LayoutWithFormController(MadxBeamlineElementsLayout), + madxBeamlineReports: MadxBeamlineReportsLayout } constructor () { diff --git a/react/src/layout/madx/allBeamlineElements.scss b/react/src/layout/madx/allBeamlineElements.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index 249a016469..26fd30fafb 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -3,8 +3,9 @@ import { FunctionComponent } from "react"; import { Badge, Button, Modal, Tab, Table, Tabs } from "react-bootstrap"; import { useDispatch, useStore } from "react-redux"; import { formActionFunctions } from "../../component/reusable/form"; +import { HoverController } from "../../component/reusable/hover"; import { Panel, ViewPanelActionButtons } from "../../component/reusable/panel"; -import { HandleFactoryWithOverrides } from "../../data/alias"; +import { ArrayAliases, HandleFactoryWithArrayAliases, HandleFactoryWithOverrides } from "../../data/alias"; import { CSchema } from "../../data/appwrapper"; import { getValueSelector, newModelFromSchema, revertDataStructure, StoreTypes } from "../../data/data"; import { Dependency } from "../../data/dependency"; @@ -15,6 +16,10 @@ import { ArrayFieldElement, ArrayFieldState } from "../../store/common"; import { ModelState } from "../../store/models"; import { Layout } from "../layout"; import { LAYOUTS } from "../layouts"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import * as Icon from "@fortawesome/free-solid-svg-icons"; +import "./allBeamlineElements.scss"; +import "./beamlines.scss"; export type TemplateSettings = { type: string, @@ -32,16 +37,40 @@ export type MadxAllBeamlineElementsConfig = { elementTemplates: TemplateSettings[] } -function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplete: (modelState: ModelState, model: string) => void, name: string, onHide: () => void }) { - let [layouts, _, updated] = useCoupledState(props.template, () => props.template.items.map((i, idx) => { - return LAYOUTS.getLayoutForSchema(i); - })) +export type MadxBeamlineElementEditorCommonProps = { + template: TemplateSettings, + onHide: () => void +} +export function MadxBeamlineElementEditor(props: MadxBeamlineElementEditorCommonProps & { + aliases: ArrayAliases +}) { + let parentHandleFactory = useContext(CHandleFactory); let schema = useContext(CSchema); + + let handleFactory = new HandleFactoryWithArrayAliases(schema, props.aliases, parentHandleFactory); + let formHandleFactory = new FormStateHandleFactory(schema, handleFactory); + let store = useStore(); - let dispatch = useDispatch(); - let parentHandleFactory = useContext(CHandleFactory); + return ( + + + + + ) +} +export function MadxBeamlineNewElementEditor(props: MadxBeamlineElementEditorCommonProps & { onComplete: (modelState: ModelState, model: string) => void, name: string }) { + let parentHandleFactory = useContext(CHandleFactory); + let schema = useContext(CSchema); + let store = useStore(); + let dispatch = useDispatch(); let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [ { fake: props.template.modelName, @@ -52,25 +81,65 @@ function BeamlineNewElementEditor(props: { template: TemplateSettings, onComplet return ( - - - {props.template.name} - - - {layouts.map((l, idx) => { - let Comp = l.component; - return ; - })} - - { - overridesHandleFactory.save(store.getState(), dispatch) - props.onHide(); - }} onCancel={props.onHide} canSave={overridesHandleFactory.isValid(store.getState())}/> - + { + overridesHandleFactory.save(store.getState(), dispatch) + props.onHide(); + }} + formCancel={props.onHide} + /> ) } +// TODO: garsuga, this is more generic than i thought, can easily be made into a common component +export function MadxBeamlineElementEditorBase(props: MadxBeamlineElementEditorCommonProps & { + formSave: () => void, + formCancel: () => void, + canSave: boolean +}) { + let [layouts, _, updated] = useCoupledState(props.template, () => { + if(!props.template) { + return undefined; + } + return props.template.items.map((i, idx) => { + return LAYOUTS.getLayoutForSchema(i); + }) + }) + + if(!(props.template && layouts)) { + return <> + } + + return ( + + + {props.template.name} + + + {layouts.map((l, idx) => { + let Comp = l.component; + return ; + })} + + + + ) +} + +export function getTemplateSettingsByType(type: string, templates: TemplateSettings[]) { + let ret = templates.find(t => { + return t.type == type + }); + if(!ret) { + throw new Error(`could not find template settings for type=${type}, ${JSON.stringify(templates)}`) + } + return ret; +} + export class MadxAllBeamlineElementsLayout extends Layout { constructor(config: MadxAllBeamlineElementsConfig) { super(config); @@ -97,15 +166,7 @@ export class MadxAllBeamlineElementsLayout extends Layout { - let ret = this.config.elementTemplates.find(t => { - return t.type == type - }); - if(!ret) { - throw new Error(`could not find template settings for type=${type}, ${JSON.stringify(this.config.elementTemplates)}`) - } - return ret; - } + let addBeamlineElement = (template: TemplateSettings, modelValue: ModelState, model: string) => { console.log(`adding beamline element with type=${template.type}`, modelValue); @@ -148,7 +209,7 @@ export class MadxAllBeamlineElementsLayout extends Layout { ([...new Set(tg.types)].sort((a,b) => a.localeCompare(b))).map(t => { - let s = getTemplateSettingsByType(t); + let s = getTemplateSettingsByType(t, this.config.elementTemplates); return (
- - +
+ @@ -187,52 +248,74 @@ export class MadxAllBeamlineElementsLayout extends LayoutBend - { - [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { - return ( - - - - - { - elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { - if(category === "COLLIMATOR") { - console.log(`${category}`, ev.item); + + { + (hover) => { + return [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { + return ( + + + + + { + elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { + let id = ev.item._id as string; + if(category === "COLLIMATOR") { + console.log(`${category}`, ev.item); + } + return ( + + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> + + + + + { + hover.checkHover(id) && ( +
+
+ + + +
+
+ ) + } + + + + ) + }) } - return ( - - - - - - - - - - ) - }) - } - - ) - - }) - } + + ) + + }) + } + } +
Name Description
- - {category} - -
+ + {category} + +
+
+ + {ev.item.name as string} + +
+
+ {/*??? TODO: garsuga: where does description come from*/} + + {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} + + {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} +
-
- - {ev.item.name as string} - -
-
- {/*??? TODO: garsuga: where does description come from*/} - - {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} - - {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} -
{actionButtons} diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index 63b53b1a54..07d615e141 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -3,7 +3,7 @@ import { getValueSelector, revertDataStructure, StoreTypes } from "../../data/da import { FormStateHandleFactory } from "../../data/form"; import { CHandleFactory } from "../../data/handle"; import { Layout } from "../layout"; -import { TemplateSettings } from "./allBeamlineElements"; +import { getTemplateSettingsByType, MadxBeamlineElementEditor, TemplateSettings } from "./allBeamlineElements"; import { Dependency } from "../../data/dependency"; import { ArrayFieldElement, ArrayFieldState } from "../../store/common"; import { ModelState } from "../../store/models"; @@ -13,7 +13,9 @@ import { useCoupledState } from "../../hook/coupling"; import { useDispatch, useStore } from "react-redux"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; -import * as IconRegular from "@fortawesome/free-regular-svg-icons"; +import { LAYOUTS } from "../layouts"; +import { ArrayAliases } from "../../data/alias"; +import { HoverController } from "../../component/reusable/hover"; export type MadxBeamlineElmenetsConfig = { selectedBeamlineDependency: string, @@ -39,44 +41,68 @@ export class MadxBeamlineElementsLayout extends Layout; - let elementsHandle = handleFactory.createHandle(new Dependency(this.config.elementsDependency), StoreTypes.FormState).hook(); + let elementsDependency = new Dependency(this.config.elementsDependency); + let elementsHandle = handleFactory.createHandle(elementsDependency, StoreTypes.FormState).hook(); let elementsValue = revertDataStructure(elementsHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; let _allItems = [...elementsValue, ...beamlinesValue]; let findBeamlineOrElementById = (id: number): ArrayFieldElement => { return _allItems.find(i => i.item.id === id || i.item._id === id); } - console.log("selectedBeamline", selectedBeamlineHandle.value); - console.log("elementsValue", elementsValue); let currentBeamline = beamlinesValue.find(beam => beam.item.id === selectedBeamlineHandle.value).item; - console.log("currentBeamline", currentBeamline); let beamlineElements = (currentBeamline.items as number[]).map(findBeamlineOrElementById) - console.log("beamlineElements", beamlineElements); - let [hoveredElement, updateHoveredElement] = useState(undefined); + let [shownElement, updateShownElement] = useState<{ + template: TemplateSettings, + aliases: ArrayAliases + }>(undefined); return ( -
- { - beamlineElements.map(e => { - let id = (e.item._id !== undefined ? e.item._id : e.item.id) as number; - let isHovered = id === hoveredElement; - return ( -
updateHoveredElement(id)} onMouseLeave={() => isHovered && updateHoveredElement(undefined)}> - - {`${e.item.name as string}`} - -
-
- null}/> -
-
-
- ) - }) - } -
+ <> +
+ + { + (hover) => { + return beamlineElements.map(e => { + let id = (e.item._id !== undefined ? e.item._id : e.item.id) as number; + let template = e.item.type !== undefined ? getTemplateSettingsByType((e.item.type as string), this.config.elementTemplates) : undefined; + let aliases: ArrayAliases = e.item.type !== undefined ? [ + { + realSchemaName: e.item.type as string, + realDataLocation: { + modelName: elementsDependency.modelName, + fieldName: elementsDependency.fieldName, + index: elementsValue.findIndex(e => e.item._id === id) + }, + fake: e.item.type as string + } + ] : undefined; + return ( +
hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> + { + updateShownElement({ + template, + aliases + }) + } + }> + {`${e.item.name as string}`} + +
+
+ null}/> +
+
+
+ ) + }) + } + } +
+
+ {shownElement && updateShownElement(undefined)}/>} + ) } } diff --git a/react/src/layout/madx/beamlineReports.tsx b/react/src/layout/madx/beamlineReports.tsx new file mode 100644 index 0000000000..2398103bc2 --- /dev/null +++ b/react/src/layout/madx/beamlineReports.tsx @@ -0,0 +1,180 @@ +import React, { FunctionComponent, useContext, useEffect, useRef, useState } from "react"; +import { CReportEventManager, ReportEventManager } from "../../data/report"; +import { Layout } from "../layout"; +import { v4 as uuidv4 } from 'uuid'; +import { CRouteHelper } from "../../utility/route"; +import { ResponseHasState } from "../../utility/compute"; +import { useDispatch, useSelector, useStore } from "react-redux"; +import { modelActions, modelSelectors } from "../../store/models"; +import { CHandleFactory } from "../../data/handle"; +import { newModelFromSchema, StoreType, StoreTypes } from "../../data/data"; +import { CSchema } from "../../data/appwrapper"; +import { LAYOUTS } from "../layouts"; +import { HandleFactoryWithArrayAliases, HandleFactoryWithOverrides, HandleFactoryWithSimpleAliases } from "../../data/alias"; + +export type MadxBeamlineReportConfig = { + type: 'histogram' | 'matchSummary' | 'graph2d', + items: SchemaLayoutJson[], + outputInfoUsage: { + modelAlias: string, + schemaModel: string, + xDependency: string, + xDefault: string, + y1Dependency: string, + y1Default: string, + y2Dependency: string, + y2Default: string, + y3Dependency: string, + y3Default: string + } +} + +export type MadxBeamlineReportsConfig = { + animationGroup: string, + reports: MadxBeamlineReportConfig[] +} + +export type OutputInfo = { + filename: string, + isHistogram: boolean, + modelKey: string, + modelAlias: string, + pageCount: number, + plottableColumns: string[], + _version: string +} + +export type OutputInfos = OutputInfo[] + +export class MadxBeamlineReportsLayout extends Layout { + childLayouts: {[key: string]: Layout[]} = undefined; + + constructor(config: MadxBeamlineReportsConfig) { + super(config); + + this.childLayouts = Object.fromEntries(this.config.reports.map(r => { + return [ + r.type, + (r.items || []).map(i => LAYOUTS.getLayoutForSchema(i)) + ] + })) + } + + component: FunctionComponent<{ [key: string]: any; }> = (props) => { + let reportEventManager = useContext(CReportEventManager); + let routeHelper = useContext(CRouteHelper); + let reportEventsVersionRef = useRef(uuidv4()); + + // make sure this component receives the first update + let customReportEventManager = new ReportEventManager(routeHelper); + + let [lastSimulationData, updateLastSimulationData] = useState(undefined); + let [outputInfo, updateOutputInfo] = useState(undefined); + + useEffect(() => { + reportEventManager.addListener(reportEventsVersionRef.current, this.config.animationGroup, { + onReportData: (simulationData) => { + updateOutputInfo(simulationData.outputInfo as OutputInfos); + updateLastSimulationData(simulationData); + } + }) + + return () => { + reportEventManager.clearListenersForKey(reportEventsVersionRef.current); + } + }, []) + + useEffect(() => { + if(lastSimulationData !== undefined) { + customReportEventManager.handleSimulationData(this.config.animationGroup, lastSimulationData); + } + }, [lastSimulationData]) + + return ( + + {(outputInfo || []).map(o => { + let config = this.config.reports.find(r => r.type === (o.isHistogram ? "histogram" : "graph2d")) + return ( + + ) + })} + + ) + } +} + +export function MadxBeamlineReportComponent(props: { + config: MadxBeamlineReportConfig, + outputInfo: OutputInfo, + childLayouts: Layout[] +}) { + // update the report model to make sure it exists + // also add x, y1,... + // render child layouts + + let handleFactory = useContext(CHandleFactory); + let schema = useContext(CSchema); + let store = useStore(); + let dispatch = useDispatch(); + + let chosenNames = []; + let setPlotColumn = (dep: Dependency, defaultColumn: string) => { + let handle = handleFactory.createHandle(dep, StoreTypes.Models).hook(); + let v = handle.value; + if(v === undefined) { + if(defaultColumn) { + v = defaultColumn; + } else { + v = props.outputInfo.plottableColumns.find(n => !chosenNames.includes(n)); + } + } + chosenNames.push(v); + handle.write(v, store.getState(), dispatch); + } + + let [hasInit, updateHasInit] = useState(false); + + let modelNames = useSelector(modelSelectors.selectModelNames()); + useEffect(() => { + if(!modelNames.includes(props.outputInfo.modelKey)) { + let schemaModel = schema.models[props.config.outputInfoUsage.schemaModel]; + let nm = newModelFromSchema(schemaModel, {}); + dispatch(modelActions.updateModel({ + name: props.outputInfo.modelKey, + value: nm + })) + } + + ["x", "y1", "y2", "y3"].forEach(n => { + setPlotColumn(new Dependency(props.config.outputInfoUsage[`${n}Dependency`]), props.config.outputInfoUsage[`${n}Default`] || undefined) + }) + + updateHasInit(true); + }) + + let aliasedHandleFactory = new HandleFactoryWithSimpleAliases(schema, [{ + real: props.outputInfo.modelKey, + fake: props.outputInfo.modelAlias + }], handleFactory); + + let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [{ + value: { + modelName: props.outputInfo.modelKey, + title: "Report" + }, + fake: "outputInfo" + }], aliasedHandleFactory); + + return ( + <> + {hasInit && ( + + {(props.childLayouts || []).map((l, i) => { + let Comp = l.component; + return + })} + + )} + + ) +} diff --git a/react/src/layout/madx/beamlines.scss b/react/src/layout/madx/beamlines.scss new file mode 100644 index 0000000000..edddf03396 --- /dev/null +++ b/react/src/layout/madx/beamlines.scss @@ -0,0 +1,24 @@ +.popover-buttons { + flex-flow: row nowrap; + justify-content: flex-end; + display: flex; + align-items: normal; + position: absolute; + right: 0px; + white-space: nowrap; +} + +.popover-buttons-outer { + width: 0; + position: relative; + display: inline-block; +} + +.popover-button { + margin-left: 10px; + color: white !important; +} + +table > tr, table > thead, table > tbody { + width: 100%; +} diff --git a/react/src/layout/madx/beamlinesPicker.tsx b/react/src/layout/madx/beamlinesPicker.tsx index 804ec71f74..61ab498b85 100644 --- a/react/src/layout/madx/beamlinesPicker.tsx +++ b/react/src/layout/madx/beamlinesPicker.tsx @@ -2,12 +2,14 @@ import React, { useState } from "react" import { FunctionComponent, useContext } from "react" import { Button, Table } from "react-bootstrap" import { useDispatch, useStore } from "react-redux" +import { HoverController } from "../../component/reusable/hover" import { StoreTypes } from "../../data/data" import { Dependency } from "../../data/dependency" import { CHandleFactory } from "../../data/handle" import { ArrayFieldState } from "../../store/common" import { ModelState } from "../../store/models" import { Layout } from "../layout" +import "./beamlines.scss"; export type MadxBeamlinesPickerConfig = { selectedBeamlineDependency: string @@ -24,7 +26,6 @@ export class MadxBeamlinesPickerLayout extends Layout let beamlinesHandle = handleFactory.createHandle(new Dependency(this.config.beamlinesDependency), StoreTypes.Models).hook(); let beamlines: ArrayFieldState = beamlinesHandle.value as ArrayFieldState; - let [hoveredBeamline, updateHoveredBeamline] = useState(undefined); let selectBeamline = (id: number) => { if(id !== selectedBeamline) { selectedBeamlineIdHandle.write(id, store.getState(), dispatch); @@ -32,7 +33,7 @@ export class MadxBeamlinesPickerLayout extends Layout } return ( - +
+ { - beamlines.map(bl => bl.item).map(bl => { - let name = bl.name as string; - let id = bl.id as number; - let isHovered = hoveredBeamline === id; - let isSelected = selectedBeamline === id; - return ( - updateHoveredBeamline(id)} onMouseLeave={() => isHovered ? updateHoveredBeamline(undefined) : undefined} style={ - { - backgroundColor: isSelected ? "#dff0d8" : undefined, - /*filter: isHovered ? "brightness(75%)" : undefined*/ - } - }> - - - - - - ) - }) + (hover) => { + return beamlines.map(bl => bl.item).map(bl => { + let name = bl.name as string; + let id = bl.id as number; + let isSelected = selectedBeamline === id; + return ( + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)} style={ + { + backgroundColor: isSelected ? "#dff0d8" : undefined, + /*filter: isHovered ? "brightness(75%)" : undefined*/ + } + }> + + + + + { + hover.checkHover(id) && ( +
+
+ + +
+
+ ) + } + + ) + }) + } } +
@@ -50,40 +51,53 @@ export class MadxBeamlinesPickerLayout extends Layout
- {`${name}`} - - {/* TODO: description */} - - {(bl.length as number).toPrecision(4)} - - - {isHovered ? ( - - ) : (bl.angle as number).toPrecision(4)} -
+ {`${name}`} + + {/* TODO: description */} + + {(bl.length as number).toPrecision(4)} + + + {(bl.angle as number).toPrecision(4)} +
) diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index 10d17c0a85..f285bb2b2d 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -17,9 +17,9 @@ import { SchemaLayout } from "../utility/schema"; import { CRouteHelper } from "../utility/route"; import { ModelState } from "../store/models"; import { useShown } from "../hook/shown"; -import { CHandleFactory, DependencyReader, useModelValue } from "../data/handle"; +import { CHandleFactory, DependencyReader } from "../data/handle"; import { StoreTypes, ValueSelectors } from "../data/data"; -import { interpolate } from "../utility/string"; +import { interpolate, InterpolationBase } from "../utility/string"; export type ReportVisualProps = { data: L, model: ModelState }; @@ -58,12 +58,12 @@ export class AutoRunReportLayout extends Layout { let [simulationData, updateSimulationData] = useState(undefined); let simulationPollingVersionRef = useRef(uuidv4()) - let [model, updateModel] = useState(undefined); + //let model = useModelValue(report, StoreTypes.Models); + let model = handleFactory.createModelHandle(report, StoreTypes.Models).hook().value; useEffect(() => { updateSimulationData(undefined); simulationInfoPromise.then(({ models, simulationId }) => { - updateModel(models[report]); pollRunReport(routeHelper, { appName, models, @@ -166,7 +166,7 @@ export type ManualRunReportConfig = { reportName: string, reportGroupName: string, frameIdFields: string[], - shown: string, + shown: string } export class ManualRunReportLayout extends Layout { @@ -179,13 +179,15 @@ export class ManualRunReportLayout extends Layout { } component = (props: LayoutProps<{}>) => { - let { reportName, reportGroupName, frameIdFields } = this.config; + let { reportGroupName, frameIdFields } = this.config; + let handleFactory = useContext(CHandleFactory); + let reportName = interpolate(this.config.reportName).withDependencies(handleFactory, StoreTypes.Models).raw(); let showAnimationController = 'showAnimationController' in this.config ? !!this.config.showAnimationController : true; let shown = useShown(this.config.shown, true, StoreTypes.Models); - //let model = getModelValues([reportName], modelsWrapper, store.getState())[reportName]; - let reportModel = useModelValue(reportName, StoreTypes.Models); + //let reportModel = useModelValue(reportName, StoreTypes.Models); + let reportModel = handleFactory.createModelHandle(reportName, StoreTypes.Models).hook().value; let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); return ( <> diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 330cb4adc4..9c36893e2f 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -9101,76 +9101,141 @@ { "layout": "panel", "config": { - "advanced": [ + "name": "simulationStatus", + "title": "Simulation Status", + "basic": [ { - "layout": "hStack", + "layout": "startSimulation", "config": { - "items": [ - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Horizontal" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.x" - ] + "reportGroupName": "animation" + } + } + ] + } + }, + { + "layout": "madxBeamlineReports", + "config": { + "animationGroup": "animation", + "reports": [ + { + "type": "graph2d", + "outputInfoUsage": { + "schemaModel": "elementAnimation", + "modelAlias": "elementAnimation", + "xDependency": "elementAnimation.x", + "xDefault": "s", + "y1Dependency": "elementAnimation.y1", + "y1Default": null, + "y2Dependency": "elementAnimation.y2", + "y2Default": null, + "y3Dependency": "elementAnimation.y3", + "y3Default": null + }, + "items": [ + { + "layout": "panel", + "config": { + "title": "$(outputInfo.title)", + "basic": [ + { + "layout": "manualRunReport", + "config": { + "reportGroupName": "animation", + "reportName": "$(outputInfo.modelName)", + "frameIdFields": [ + "elementAnimation.x", + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3", + "elementAnimation.histogramBins", + "elementAnimation.plotRangeType", + "elementAnimation.horizontalSize", + "elementAnimation.horizontalOffset", + "elementAnimation.verticalSize", + "elementAnimation.verticalOffset" + ], + "reportLayout": { + "layout": "graph2d", + "config": {} } } - ] - } - }, - { - "layout": "vStack", - "config": { - "items": [ - { - "layout": "text", - "config": { - "type": "header", - "align": "left", - "text": "Vertical" - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.y1", - "twissFromParticlesAnimation.y2", - "twissFromParticlesAnimation.y3" - ] - } + } + ], + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } + } + ] + } + } + ] } - ] - } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.includeLattice", + "elementAnimation.notes" + ] + } + } + ] } - ] - } - }, - { - "layout": "fieldList", - "config": { - "fields": [ - "twissFromParticlesAnimation.includeLattice", - "twissFromParticlesAnimation.notes" - ] - } + } + ] } - ], - "title": "Twiss From Particles" - }, - "_NAME": "twissFromParticlesAnimation" + ] + } } + ] } } diff --git a/sirepo/template/lattice.py b/sirepo/template/lattice.py index 6ec42b4cd2..095fb0db12 100644 --- a/sirepo/template/lattice.py +++ b/sirepo/template/lattice.py @@ -668,33 +668,31 @@ def iterate_models(self, iterator, name=None): By default the commands and elements containers are iterated. """ iterator.id_map = self.id_map - a = [self.data.models[name]] if name else [map(lambda i: i.item, self.data.models.elements.elements), self.data.models.commands] - for e in a: - for m in e: - model_schema = self.schema.model[self.model_name_for_data(m)] - iterator.start(m) - for k in sorted(m): - if k in model_schema: - iterator.field(m, model_schema[k], k) - iterator.end(m) + e = [self.data.models[name]] if name else self.data.models.commands + list(map(lambda i: i.item, self.data.models.elements.elements)) + for m in e: + model_schema = self.schema.model[self.model_name_for_data(m)] + iterator.start(m) + for k in sorted(m): + if k in model_schema: + iterator.field(m, model_schema[k], k) + iterator.end(m) return iterator @classmethod def max_id(cls, data): max_id = 1 - a = [] + e = [] if "elements" in data.models: - a += map(lambda i: i.item, data.models.elements.elements) + e += map(lambda i: i.item, data.models.elements.elements) if "lattice" in data.models: - a += map(lambda i: i.item, data.models.lattice.beamlines) + e += map(lambda i: i.item, data.models.lattice.beamlines) if "commands" in data.models: - a += data.models.commands - for e in a: - for m in e: - assert "_id" in m or "id" in m, "Missing id: {}".format(m) - i = m._id if "_id" in m else m.id - if i > max_id: - max_id = i + e += data.models.commands + for m in e: + assert "_id" in m or "id" in m, "Missing id: {}".format(m) + i = m._id if "_id" in m else m.id + if i > max_id: + max_id = i return max_id @classmethod diff --git a/sirepo/template/madx.py b/sirepo/template/madx.py index 9a9cceb075..cc3849d506 100644 --- a/sirepo/template/madx.py +++ b/sirepo/template/madx.py @@ -434,7 +434,7 @@ def to_string(value): def uniquify_elements(data): def _do_unique(elem_ids): - ae = map(lambda i: i.item, data.model.elements.elements) + ae = map(lambda i: i.item, data.models.elements.elements) element_map = PKDict({e._id: e for e in ae}) names = set([e.name for e in ae]) max_id = LatticeUtil.max_id(data) @@ -963,7 +963,7 @@ def _output_info(run_dir): PKDict( modelKey="twissFromParticlesAnimation", filename=f.filename, - isHistogram=True, + isHistogram=False, plottableColumns=PTC_OBSERVE_TWISS_COLS, pageCount=0, ), From 8955d0861ac3462388c8249ba3fb0d4584691d71 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 17 May 2023 22:35:47 +0000 Subject: [PATCH 45/68] complete manual reports --- react/src/data/alias.ts | 13 +- react/src/data/data.ts | 1 + react/src/layout/madx/beamlineReports.tsx | 63 +++++----- react/src/layout/report.tsx | 15 ++- .../static/react-json/madx-schema.json | 114 ++++++++++++++++++ sirepo/template/lattice.py | 7 +- 6 files changed, 173 insertions(+), 40 deletions(-) diff --git a/react/src/data/alias.ts b/react/src/data/alias.ts index f20356dc11..5618cba0ca 100644 --- a/react/src/data/alias.ts +++ b/react/src/data/alias.ts @@ -42,10 +42,7 @@ export class HandleFactoryWithArrayAliases extends HandleFactory { } createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle> => { - console.log(`alias handle factory creating handle for ${dependency.getDependencyString()}`); let alias = this.aliases.find(a => a.fake === dependency.modelName); - console.log(`alias=${alias}`); - console.log(`aliases`, this.aliases); let getAE = this.getArrayElementFromParentHandle; if(alias !== undefined) { let edh = this.emptyAliasedHandle(alias.realDataLocation, type); @@ -141,8 +138,6 @@ export class HandleFactoryWithOverrides extends HandleFactory { overrides.forEach(ov => { ov.formValue = mapProperties(ov.value, (n, i) => initialFormStateFromValue(i)); }) - - console.log("overrides", overrides); } save: FormActionFunc = (state: any, dispatch: Dispatch) => { @@ -182,14 +177,14 @@ export class HandleFactoryWithOverrides extends HandleFactory { createHandle = (dependency: Dependency, type: StoreType): EmptyDataHandle> => { let override = this.overrides.find(a => a.fake === dependency.modelName); let inst = this; - console.log(`resolving dependency=${dependency.getDependencyString()}`) + //console.log(`resolving dependency=${dependency.getDependencyString()}`) if(override !== undefined) { - console.log(`overriding handle for dependency=${dependency.getDependencyString()}, override=${JSON.stringify(override)}`); + //console.log(`overriding handle for dependency=${dependency.getDependencyString()}, override=${JSON.stringify(override)}`); return new (class implements EmptyDataHandle { private createDummyHandle(): DataHandle { let mv = type === StoreTypes.Models ? override.value : override.formValue; let fv = mv[dependency.fieldName] as F; - console.log(`${dependency.getDependencyString()} = ${JSON.stringify(fv)}`) + //console.log(`${dependency.getDependencyString()} = ${JSON.stringify(fv)}`) return new (class extends DataHandle { write(value: F, state: any, dispatch: Dispatch) { inst.notify(dependency); @@ -198,9 +193,7 @@ export class HandleFactoryWithOverrides extends HandleFactory { if(type === StoreTypes.FormState) { let type = inst.schema.models[dependency.modelName][dependency.fieldName].type let rawValue = revertDataStructure(value as any, getValueSelector(StoreTypes.FormState)); - console.log("rawValue", rawValue); let v = type.toModelValue(rawValue); - console.log("value", v); override.value[dependency.fieldName] = v; } } diff --git a/react/src/data/data.ts b/react/src/data/data.ts index 3f4f363458..f49a5af96b 100644 --- a/react/src/data/data.ts +++ b/react/src/data/data.ts @@ -39,6 +39,7 @@ export const getValueSelector = (storeType: StoreType): ((v: F) => an } export function newModelFromSchema(modelSchema: SchemaModel, overrides: {[key: string]: any}): ModelState { + console.log("modelSchema", modelSchema); let defaults = Object.fromEntries(Object.entries(modelSchema).filter(([name, value]) => value.defaultValue !== undefined).map(([name, value]) => [name, value.defaultValue])) return Object.assign(defaults, overrides); } diff --git a/react/src/layout/madx/beamlineReports.tsx b/react/src/layout/madx/beamlineReports.tsx index 2398103bc2..86e010817b 100644 --- a/react/src/layout/madx/beamlineReports.tsx +++ b/react/src/layout/madx/beamlineReports.tsx @@ -7,10 +7,11 @@ import { ResponseHasState } from "../../utility/compute"; import { useDispatch, useSelector, useStore } from "react-redux"; import { modelActions, modelSelectors } from "../../store/models"; import { CHandleFactory } from "../../data/handle"; -import { newModelFromSchema, StoreType, StoreTypes } from "../../data/data"; +import { newModelFromSchema, StoreTypes } from "../../data/data"; import { CSchema } from "../../data/appwrapper"; import { LAYOUTS } from "../layouts"; -import { HandleFactoryWithArrayAliases, HandleFactoryWithOverrides, HandleFactoryWithSimpleAliases } from "../../data/alias"; +import { HandleFactoryWithOverrides, HandleFactoryWithSimpleAliases } from "../../data/alias"; +import { Dependency } from "../../data/dependency"; export type MadxBeamlineReportConfig = { type: 'histogram' | 'matchSummary' | 'graph2d', @@ -38,7 +39,6 @@ export type OutputInfo = { filename: string, isHistogram: boolean, modelKey: string, - modelAlias: string, pageCount: number, plottableColumns: string[], _version: string @@ -93,9 +93,12 @@ export class MadxBeamlineReportsLayout extends Layout return ( {(outputInfo || []).map(o => { - let config = this.config.reports.find(r => r.type === (o.isHistogram ? "histogram" : "graph2d")) + let type = (o.isHistogram ? "heatplot" : "graph2d"); + console.log("type", type); + let config = this.config.reports.find(r => r.type === type); + return ( - + ) })} @@ -119,32 +122,36 @@ export function MadxBeamlineReportComponent(props: { let chosenNames = []; let setPlotColumn = (dep: Dependency, defaultColumn: string) => { - let handle = handleFactory.createHandle(dep, StoreTypes.Models).hook(); - let v = handle.value; - if(v === undefined) { - if(defaultColumn) { - v = defaultColumn; - } else { - v = props.outputInfo.plottableColumns.find(n => !chosenNames.includes(n)); + let m = handleFactory.createModelHandle(dep.modelName, StoreTypes.Models).initialize(store.getState()).value; + + if(m) { + let handle = handleFactory.createHandle(dep, StoreTypes.Models).initialize(store.getState()); + let v = handle.value; + if(v !== undefined) { + chosenNames.push(v); + return; } - } + } else { + m = newModelFromSchema(schema.models[props.config.outputInfoUsage.schemaModel], {}); + dispatch(modelActions.updateModel({ + name: dep.modelName, + value: m + })) + } + + let v = undefined; + if(defaultColumn) { + v = defaultColumn; + } else { + v = props.outputInfo.plottableColumns.find(n => !chosenNames.includes(n)); + } chosenNames.push(v); - handle.write(v, store.getState(), dispatch); + handleFactory.createHandle(dep, StoreTypes.Models).initialize(store.getState()).write(v, store.getState(), dispatch); } let [hasInit, updateHasInit] = useState(false); - let modelNames = useSelector(modelSelectors.selectModelNames()); useEffect(() => { - if(!modelNames.includes(props.outputInfo.modelKey)) { - let schemaModel = schema.models[props.config.outputInfoUsage.schemaModel]; - let nm = newModelFromSchema(schemaModel, {}); - dispatch(modelActions.updateModel({ - name: props.outputInfo.modelKey, - value: nm - })) - } - ["x", "y1", "y2", "y3"].forEach(n => { setPlotColumn(new Dependency(props.config.outputInfoUsage[`${n}Dependency`]), props.config.outputInfoUsage[`${n}Default`] || undefined) }) @@ -154,7 +161,7 @@ export function MadxBeamlineReportComponent(props: { let aliasedHandleFactory = new HandleFactoryWithSimpleAliases(schema, [{ real: props.outputInfo.modelKey, - fake: props.outputInfo.modelAlias + fake: props.config.outputInfoUsage.modelAlias }], handleFactory); let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [{ @@ -167,14 +174,16 @@ export function MadxBeamlineReportComponent(props: { return ( <> + {hasInit && ( - + <> {(props.childLayouts || []).map((l, i) => { let Comp = l.component; return })} - + )} + ) } diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index f285bb2b2d..a057ac4bf3 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -108,16 +108,22 @@ export function useAnimationReader(reportName: string, reportGroupName: string, let reportEventsVersionRef = useRef(uuidv4()) let frameIdHandles = frameIdFields.map(f => new Dependency(f)).map(d => handleFactory.createHandle(d, StoreTypes.Models).hook()); - function reportStatus(reportName, simulationData) { + function reportStatus(reportName: string, simulationData: ResponseHasState) { if (simulationData.reports) { for (const r of simulationData.reports) { if (r.modelName === reportName) { return { - frameCount: r.frameCount || r.lastUpdateTime || 0, + frameCount: r.frameCount !== undefined ? r.frameCount : (r.lastUpdateTime || 0), hasAnimationControls: ! r.lastUpdateTime, }; } } + } else if(simulationData.outputInfo) { + let frameCount = (simulationData.outputInfo as any[]).find(o => o.modelKey === reportName).pageCount + return { + frameCount, + hasAnimationControls: frameCount > 1 + } } return { frameCount: 0, @@ -131,10 +137,12 @@ export function useAnimationReader(reportName: string, reportGroupName: string, updateAnimationReader(undefined); }, onReportData: (simulationData: ResponseHasState) => { + console.log("onData"); simulationInfoPromise.then(({models, simulationId}) => { let { computeJobHash, computeJobSerial } = simulationData; const s = reportStatus(reportName, simulationData); if (!animationReader || s.frameCount !== animationReader?.frameCount) { + console.log("frameCount", s.frameCount); if (s.frameCount > 0) { let newAnimationReader = new AnimationReader(routeHelper, { reportName, @@ -189,6 +197,9 @@ export class ManualRunReportLayout extends Layout { //let reportModel = useModelValue(reportName, StoreTypes.Models); let reportModel = handleFactory.createModelHandle(reportName, StoreTypes.Models).hook().value; let animationReader = useAnimationReader(reportName, reportGroupName, frameIdFields); + console.log("shown", shown); + console.log("reportLayout", this.reportLayout); + console.log("animationReader", animationReader); return ( <> {shown && this.reportLayout && diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 9c36893e2f..59925c6cc6 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -9231,6 +9231,120 @@ } } ] + }, + { + "type": "heatplot", + "outputInfoUsage": { + "schemaModel": "elementAnimation", + "modelAlias": "elementAnimation", + "xDependency": "elementAnimation.x", + "xDefault": "s", + "y1Dependency": "elementAnimation.y1", + "y1Default": null, + "y2Dependency": "elementAnimation.y2", + "y2Default": null, + "y3Dependency": "elementAnimation.y3", + "y3Default": null + }, + "items": [ + { + "layout": "panel", + "config": { + "title": "$(outputInfo.title)", + "basic": [ + { + "layout": "manualRunReport", + "config": { + "reportGroupName": "animation", + "reportName": "$(outputInfo.modelName)", + "frameIdFields": [ + "elementAnimation.x", + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3", + "elementAnimation.histogramBins", + "elementAnimation.plotRangeType", + "elementAnimation.horizontalSize", + "elementAnimation.horizontalOffset", + "elementAnimation.verticalSize", + "elementAnimation.verticalOffset" + ], + "reportLayout": { + "layout": "heatplot", + "config": {} + } + } + } + ], + "advanced": [ + { + "layout": "hStack", + "config": { + "items": [ + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Horizontal" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.x" + ] + } + } + ] + } + }, + { + "layout": "vStack", + "config": { + "items": [ + { + "layout": "text", + "config": { + "type": "header", + "align": "left", + "text": "Vertical" + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.y1", + "elementAnimation.y2", + "elementAnimation.y3" + ] + } + } + ] + } + } + ] + } + }, + { + "layout": "fieldList", + "config": { + "fields": [ + "elementAnimation.includeLattice", + "elementAnimation.notes" + ] + } + } + ] + } + } + ] } ] } diff --git a/sirepo/template/lattice.py b/sirepo/template/lattice.py index 095fb0db12..af485f5f84 100644 --- a/sirepo/template/lattice.py +++ b/sirepo/template/lattice.py @@ -668,7 +668,12 @@ def iterate_models(self, iterator, name=None): By default the commands and elements containers are iterated. """ iterator.id_map = self.id_map - e = [self.data.models[name]] if name else self.data.models.commands + list(map(lambda i: i.item, self.data.models.elements.elements)) + o = None + if name == "elements": + o = self.data.models.elements.elements + elif name == "beamlines": + o = self.data.models.lattice.beamlines + e = (list(map(lambda i: i.item, o)) if o is not None else self.data.models[name]) if name else self.data.models.commands + list(map(lambda i: i.item, self.data.models.elements.elements)) for m in e: model_schema = self.schema.model[self.model_name_for_data(m)] iterator.start(m) From dc7e15dbb8d35983cf918ee06eb515f1bde4aba8 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 18 May 2023 17:30:08 +0000 Subject: [PATCH 46/68] remove log --- react/src/layout/madx/beamlineReports.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/react/src/layout/madx/beamlineReports.tsx b/react/src/layout/madx/beamlineReports.tsx index 86e010817b..e98e7dbc85 100644 --- a/react/src/layout/madx/beamlineReports.tsx +++ b/react/src/layout/madx/beamlineReports.tsx @@ -94,7 +94,6 @@ export class MadxBeamlineReportsLayout extends Layout {(outputInfo || []).map(o => { let type = (o.isHistogram ? "heatplot" : "graph2d"); - console.log("type", type); let config = this.config.reports.find(r => r.type === type); return ( From c0408279510acf89b3d10af6fa616a1ebf8d061b Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 18 May 2023 17:54:26 +0000 Subject: [PATCH 47/68] fix error on edit --- react/src/data/handle.ts | 3 +++ react/src/layout/madx/allBeamlineElements.tsx | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/react/src/data/handle.ts b/react/src/data/handle.ts index 42f90bba31..495232e325 100644 --- a/react/src/data/handle.ts +++ b/react/src/data/handle.ts @@ -58,8 +58,11 @@ export class BaseHandleFactory extends HandleFactory { let ms = this.modelSelector(dependency.modelName, type); let mac = getModelWriteActionCreator(type); let cdh = (value: F): DataHandle => { + let lastValue = value; return new (class extends DataHandle { write = (value: F, state: any, dispatch: Dispatch) => { + console.log(`writing value to ${dependency.getDependencyString()}`, value); + console.log(`last value for ${dependency.getDependencyString()}`, lastValue); let mv = {...state[type.name][dependency.modelName]}; mv[dependency.fieldName] = value; dispatch(mac(dependency.modelName, mv)); diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index 26fd30fafb..a30fd41ca9 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -281,10 +281,10 @@ export class MadxAllBeamlineElementsLayout extends Layout - {ev.item.l !== undefined ? `${(ev.item.l as number).toPrecision(4)}m` : ""} + {ev.item.l !== undefined ? `${(ev.item.l)}m` : ""} - {ev.item.angle !== undefined ? (ev.item.angle as number).toPrecision(3) : ""} + {ev.item.angle !== undefined ? `${ev.item.angle}` : ""} { hover.checkHover(id) && ( From f891dfd8add180cee5d728876c8c41ef1accf134 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 18 May 2023 19:11:31 +0000 Subject: [PATCH 48/68] fix route formatting --- react/src/utility/route.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/react/src/utility/route.ts b/react/src/utility/route.ts index 44f21e29d7..1a3d83dbad 100644 --- a/react/src/utility/route.ts +++ b/react/src/utility/route.ts @@ -53,7 +53,7 @@ export class RouteHelper { let p = match[2]; // matched word allParamNames.push(p); let s = match[3] || ""; // optional / - let e = match.index + match.length; + let e = match.index + match[0].length; if(!params || !Object.keys(params).includes(p)) { if(!o) { From 3ff2fa645d9d25dbc84cae115423b37bb68d500c Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 18 May 2023 22:20:30 +0000 Subject: [PATCH 49/68] add beamline elements editor functions and fix simulation info handling --- react/src/component/app.tsx | 4 +- react/src/component/login/guest.tsx | 2 +- react/src/component/login/login.tsx | 2 +- react/src/component/reusable/form.tsx | 1 + react/src/component/simulation.tsx | 120 ++++++++------- react/src/data/appwrapper.ts | 10 +- react/src/data/form.ts | 2 - react/src/data/middleware/middleware.ts | 6 +- react/src/data/middleware/save.ts | 32 ++-- react/src/hook/setup.ts | 6 +- react/src/hook/simulationInfo.ts | 7 + react/src/layout/input/enum.tsx | 23 +-- react/src/layout/input/file.tsx | 53 ++++--- react/src/layout/madx/allBeamlineElements.tsx | 68 +++++++-- react/src/layout/madx/beamlineElements.tsx | 2 + react/src/layout/navbar.tsx | 1 - react/src/layout/panel.tsx | 2 - react/src/layout/report.tsx | 143 +++++++++--------- react/src/layout/shadow/beamline.tsx | 4 +- .../static/react-json/madx-schema.json | 2 + 20 files changed, 275 insertions(+), 215 deletions(-) create mode 100644 react/src/hook/simulationInfo.ts diff --git a/react/src/component/app.tsx b/react/src/component/app.tsx index 9adcda8c3f..f03e1d48ef 100644 --- a/react/src/component/app.tsx +++ b/react/src/component/app.tsx @@ -16,7 +16,7 @@ import { getAppCombinedSchema } from "../utility/schema"; export const AppContextWrapper = (props) => { let appName = useContext(CAppName); - const [hasAppSchema, schema] = useSetup(true, getAppCombinedSchema(appName)); + const [hasAppSchema, schema] = useSetup(true, () => getAppCombinedSchema(appName)); if(hasAppSchema) { const routeHelper = new RouteHelper(appName, schema); @@ -69,7 +69,7 @@ export const AppRoot = (props) => { export const SimulationListInitializer = (props) => { let appWrapper = useContext(CAppWrapper); - const [hasSimulationList, simulationList] = useSetup(true, appWrapper.getSimulationList()); + const [hasSimulationList, simulationList] = useSetup(true, () => appWrapper.getSimulationList()); return ( <> {hasSimulationList && diff --git a/react/src/component/login/guest.tsx b/react/src/component/login/guest.tsx index b415255209..fae1270a21 100644 --- a/react/src/component/login/guest.tsx +++ b/react/src/component/login/guest.tsx @@ -12,7 +12,7 @@ export function LoginWithGuest(props) { let appWrapper = useContext(CAppWrapper); let loginStatusRef = useContext(CLoginStatusRef); - let [hasLoggedIn, _] = useSetup(true, appWrapper.doGuestLogin().then(() => updateLoginStatusRef(loginStatusRef, appWrapper))); + let [hasLoggedIn, _] = useSetup(true, () => appWrapper.doGuestLogin().then(() => updateLoginStatusRef(loginStatusRef, appWrapper))); return ( hasLoggedIn && diff --git a/react/src/component/login/login.tsx b/react/src/component/login/login.tsx index f32e9872ad..0dddce949b 100644 --- a/react/src/component/login/login.tsx +++ b/react/src/component/login/login.tsx @@ -23,7 +23,7 @@ export const LoginRouter = (props) => { let routeHelper = useContext(CRouteHelper); let loginStatusRef = useRef(undefined); let location = useLocation(); - const [hasLoginStatus, _] = useSetup(true, updateLoginStatusRef(loginStatusRef, appWrapper)); + const [hasLoginStatus, _] = useSetup(true, () => updateLoginStatusRef(loginStatusRef, appWrapper)); const isSimulations = location.pathname.startsWith(routeHelper.localRoute("simulations")); return hasLoginStatus && ( diff --git a/react/src/component/reusable/form.tsx b/react/src/component/reusable/form.tsx index 98725da936..2c4c3d32cc 100644 --- a/react/src/component/reusable/form.tsx +++ b/react/src/component/reusable/form.tsx @@ -94,6 +94,7 @@ export function FormStateInitializer(props) { value: mapProperties(value, (_, fv) => initialFormStateFromValue(fv)) })); }); + console.log("fs store", store.getState()); updateHasInit(true); }) diff --git a/react/src/component/simulation.tsx b/react/src/component/simulation.tsx index a9a3b29f89..8d09667fc7 100644 --- a/react/src/component/simulation.tsx +++ b/react/src/component/simulation.tsx @@ -18,7 +18,7 @@ import { useNavigate, useResolvedPath } from "react-router-dom"; import { CRelativeRouterHelper, CRouteHelper, RelativeRouteHelper } from "../utility/route"; import { ReportEventManager } from "../data/report"; import { CReportEventManager } from "../data/report"; -import { CAppName, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { CAppName, CSchema } from "../data/appwrapper"; import { LAYOUTS } from "../layout/layouts"; import { Dependency } from "../data/dependency"; import { NavbarRightContainerId, NavToggleDropdown } from "./reusable/navbar"; @@ -35,70 +35,80 @@ import { BaseHandleFactory, CHandleFactory } from "../data/handle"; import { StoreTypes } from "../data/data"; import { useCoupledState } from "../hook/coupling"; import { middlewaresForSchema } from "../data/middleware/middleware"; +import { useSimulationInfo } from "../hook/simulationInfo"; export type SimulationInfoRaw = { models: StoreState, - simulationType: string, - version: string -} + simulationType: string +} -export type SimulationInfo = SimulationInfoRaw & { - simulationId: string +export type SimulationInfo = { + simulationType: string, + simulationId: string, + version: string, + name: string, + isExample: boolean, + folder: string } function SimulationInfoInitializer(props: { simulationId: string } & {[key: string]: any}) { let { simulationId } = props; let schema = useContext(CSchema); + let appName = useContext(CAppName); + let routeHelper = useContext(CRouteHelper); const [modelsStore, updateModelsStore] = useState(undefined); - let [simulationInfoPromise, updateSimulationInfoPromise] = useState(undefined); - let [hasInit, updateHasInit] = useState(false); - let appName = useContext(CAppName); - let routeHelper = useContext(CRouteHelper); + let [hasSimulationInfo, simulationInfo] = useSetup(true, () => new Promise((resolve, reject) => { + fetch(routeHelper.globalRoute("simulationData", { + simulation_type: appName, + simulation_id: simulationId, + pretty: "0" + })).then(async (resp) => { + let simulationInfo = {...(await resp.json()), simulationId} as SimulationInfoRaw; + let models = simulationInfo['models'] as StoreState; + + let _store = configureStore({ + reducer: { + [modelsSlice.name]: modelsSlice.reducer, + [formStatesSlice.name]: formStatesSlice.reducer, + }, + middleware: [...middlewaresForSchema(schema, simulationInfo)] + }) - useEffect(() => { - updateSimulationInfoPromise(new Promise((resolve, reject) => { - fetch(routeHelper.globalRoute("simulationData", { - simulation_type: appName, - simulation_id: simulationId, - pretty: "0" - })).then(async (resp) => { - let simulationInfo = {...(await resp.json() as SimulationInfoRaw), simulationId} as SimulationInfo; - let models = simulationInfo['models'] as StoreState; - - let _store = configureStore({ - reducer: { - [modelsSlice.name]: modelsSlice.reducer, - [formStatesSlice.name]: formStatesSlice.reducer, - }, - middleware: [...middlewaresForSchema(schema, simulationInfo)] - }) - - updateModelsStore(_store) - - for(let [modelName, model] of Object.entries(models)) { - _store.dispatch(modelActions.updateModel({ - name: modelName, - value: model - })) + updateModelsStore(_store) + + for(let [modelName, model] of Object.entries(models)) { + _store.dispatch(modelActions.updateModel({ + name: modelName, + value: model + })) + } + + _store.dispatch(modelActions.updateModel({ + name: "simulation", + value: { + ...models["simulation"], + ...{ + ...simulationInfo, + models: undefined + } } - - resolve(simulationInfo); - updateHasInit(true); - }) - })) - }, []) + })) + + console.log("store", _store.getState()); + + resolve(simulationInfo); + }) + })); let [handleFactory, _] = useCoupledState(schema, new BaseHandleFactory(schema)) - return hasInit && simulationInfoPromise && ( + return hasSimulationInfo && ( - - {props.children} - + {props.children} ) @@ -108,12 +118,12 @@ function SimulationCogMenu(props) { let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); let navigate = useNavigate(); - let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); + let handleFactory = useContext(CHandleFactory); let [showCopyModal, updateShowCopyModal] = useState(false); - let [hasSimualtionInfo, simulationInfo] = useSetup(true, simulationInfoPromise); + let simulationInfo = useSimulationInfo(handleFactory); let deleteSimulationPromise = (simulationId: string) => { return fetch(routeHelper.globalRoute("deleteSimulation"), { @@ -129,7 +139,7 @@ function SimulationCogMenu(props) { } let discardChanges = async () => { - let { simulationId, models: { simulation: { name }} } = simulationInfo || await simulationInfoPromise; + let { simulationId, name } = simulationInfo; await deleteSimulationPromise(simulationId); let newSimulationInfo: SimulationInfoRaw = await (await fetch(routeHelper.globalRoute("findByName", { simulation_type: appName, @@ -142,13 +152,13 @@ function SimulationCogMenu(props) { } let deleteSimulation = async () => { - let { simulationId } = simulationInfo || await simulationInfoPromise; + let { simulationId } = simulationInfo; await deleteSimulationPromise(simulationId); navigate(routeHelper.localRoute("root")); } let exportArchive = async () => { - let { simulationId, models: { simulation: { name }} } = simulationInfo || await simulationInfoPromise; + let { simulationId, name } = simulationInfo; window.open(routeHelper.globalRoute("exportArchive", { simulation_type: appName, simulation_id: simulationId, @@ -157,7 +167,7 @@ function SimulationCogMenu(props) { } let pythonSource = async () => { - let { simulationId, models: { simulation: { name }} } = simulationInfo || await simulationInfoPromise; + let { simulationId, name } = simulationInfo; let r = await fetch(routeHelper.globalRoute("pythonSource2", { simulation_type: appName }), { method: "POST", @@ -176,7 +186,7 @@ function SimulationCogMenu(props) { } let openCopy = async (newName) => { - let { simulationId, models: { simulation: { folder }} } = simulationInfo || await simulationInfoPromise; + let { simulationId, folder } = simulationInfo; let { models: { simulation: { simulationId: newSimId }} } = await (await fetch(routeHelper.globalRoute("copySimulation"), { method: "POST", headers: { @@ -198,7 +208,7 @@ function SimulationCogMenu(props) { <> { updateShowCopyModal(false); openCopy(name) @@ -209,8 +219,8 @@ function SimulationCogMenu(props) { pythonSource()}> { schema.constants.simSourceDownloadText } updateShowCopyModal(true)}> Open as a New Copy { - hasSimualtionInfo && ( - simulationInfo.models.simulation.isExample ? ( + ( + simulationInfo.isExample ? ( discardChanges()}> Discard changes to example ) : ( deleteSimulation()}> Delete diff --git a/react/src/data/appwrapper.ts b/react/src/data/appwrapper.ts index 34f51749c6..d0f243cb12 100644 --- a/react/src/data/appwrapper.ts +++ b/react/src/data/appwrapper.ts @@ -1,9 +1,6 @@ -import React, { MutableRefObject } from "react" -import { SimulationInfo, SimulationInfoRaw } from "../component/simulation" -import { StoreState } from "../store/common" -import { ModelState } from "../store/models" -import { RouteHelper } from "../utility/route" -import { Schema } from "../utility/schema" +import React, { MutableRefObject } from "react"; +import { RouteHelper } from "../utility/route"; +import { Schema } from "../utility/schema"; export type ApiSimulation = { documentationUrl: string, @@ -45,7 +42,6 @@ export type LoginStatus = { } export const CSimulationList = React.createContext(undefined); -export const CSimulationInfoPromise = React.createContext>(undefined); export const CAppName = React.createContext(undefined); export const CSchema = React.createContext(undefined); export const CLoginStatusRef = React.createContext>(undefined); diff --git a/react/src/data/form.ts b/react/src/data/form.ts index 32bd5281c9..44fc14cd90 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -77,9 +77,7 @@ export class FormStateHandleFactory extends HandleFactory { } private addToUpdated = (key: any, value: FormActions) => { - console.log("add to updated"); this.updated.put(key, value); - console.log("updated", this.updated); this.notifyListeners(); } diff --git a/react/src/data/middleware/middleware.ts b/react/src/data/middleware/middleware.ts index afa6699368..03f38b0b02 100644 --- a/react/src/data/middleware/middleware.ts +++ b/react/src/data/middleware/middleware.ts @@ -1,11 +1,11 @@ import { Middleware } from "redux"; -import { SimulationInfo } from "../../component/simulation"; +import { SimulationInfo, SimulationInfoRaw } from "../../component/simulation"; import { Schema } from "../../utility/schema"; import { saveMiddleware } from "./save"; import { shadowBeamlineSortingMiddleware } from "./shadow/beamline"; import { shadowBeamlineWatchpointReportsMiddleware } from "./shadow/watchpoint"; -export type ConfigurableMiddleware = (config: C, schema: Schema, simulationInfo: SimulationInfo) => Middleware +export type ConfigurableMiddleware = (config: C, schema: Schema, simulationInfo: SimulationInfoRaw) => Middleware export const Middlewares: {[key: string]: ConfigurableMiddleware} = { shadowWatchpointsFromBeamline: shadowBeamlineWatchpointReportsMiddleware, @@ -13,6 +13,6 @@ export const Middlewares: {[key: string]: ConfigurableMiddleware} = { save: saveMiddleware } -export function middlewaresForSchema(schema: Schema, simulationInfo: SimulationInfo): Middleware[] { +export function middlewaresForSchema(schema: Schema, simulationInfo: SimulationInfoRaw): Middleware[] { return (schema.middleware || []).map(sm => Middlewares[sm.type](sm.config, schema, simulationInfo)); } diff --git a/react/src/data/middleware/save.ts b/react/src/data/middleware/save.ts index b82d435a88..f051eafee4 100644 --- a/react/src/data/middleware/save.ts +++ b/react/src/data/middleware/save.ts @@ -1,6 +1,7 @@ -import { SimulationInfo } from "../../component/simulation"; +import { MiddlewareAPI, Store } from "redux"; +import { SimulationInfo, SimulationInfoRaw } from "../../component/simulation"; import { StoreState } from "../../store/common"; -import { ModelState } from "../../store/models"; +import { modelActions, ModelState } from "../../store/models"; import { StoreTypes } from "../data"; import { ConfigurableMiddleware } from "./middleware" @@ -9,15 +10,28 @@ export type SaveMiddlewareConfig = { maxIntervalSeconds: number } -const saveModelsToServer = (simulationInfo: SimulationInfo, models: StoreState): Promise => { - simulationInfo = {...simulationInfo}; // clone, no mutations - simulationInfo.models = models; +const saveModelsToServer = (simulationInfo: SimulationInfo, store: MiddlewareAPI): Promise => { + console.log("simulationInfo", simulationInfo) + let newInfo = { + version: simulationInfo.version, + simulationId: simulationInfo.simulationId, + simulationType: simulationInfo.simulationType, + models: store.getState()[StoreTypes.Models.name] + }; // clone, no mutations return fetch("/save-simulation", { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(simulationInfo) + body: JSON.stringify(newInfo) + }).then(async resp => { + let simInfo: SimulationInfoRaw = await resp.json(); + store.dispatch(modelActions.updateModel({ + name: "simulation", + value: simInfo.models["simulation"] + })) + + return resp; }) } @@ -25,7 +39,7 @@ export const saveMiddleware: ConfigurableMiddleware = (con let saveTimeout = undefined; let firstUpdateInSave = undefined; return store => next => action => { - if(action.type === "models/updateModel") { + if(action.type === "models/updateModel" && action.payload.name !== "simulation") { if(firstUpdateInSave === undefined) { firstUpdateInSave = Date.now(); } @@ -37,9 +51,7 @@ export const saveMiddleware: ConfigurableMiddleware = (con saveTimeout = setTimeout(() => { firstUpdateInSave = undefined; - console.log("simulationInfo", simulationInfo); - console.log("models", store.getState()[StoreTypes.Models.name]) - saveModelsToServer(simulationInfo, store.getState()[StoreTypes.Models.name]) + saveModelsToServer(store.getState()[StoreTypes.Models.name].simulation, store) }, timeUntilSave) } return next(action); diff --git a/react/src/hook/setup.ts b/react/src/hook/setup.ts index 828f95a1e8..fa6516dd34 100644 --- a/react/src/hook/setup.ts +++ b/react/src/hook/setup.ts @@ -1,19 +1,19 @@ import { useState, useEffect, useRef } from "react"; -export function useSetup(shouldRun: boolean, promise: Promise): [boolean, T] { +export function useSetup(shouldRun: boolean, promise: () => Promise): [boolean, T] { const [status, updateStatus] = useState({ completed: false, value: undefined }); const promiseHasSubscribed = useRef(false); useEffect(() => { if(shouldRun && !status.completed && !promiseHasSubscribed.current) { promiseHasSubscribed.current = true; - promise.then((v: T) => { + promise().then((v: T) => { updateStatus({ value: v, completed: true }) }) } - }); + }, []); return [status.completed, status.value]; } diff --git a/react/src/hook/simulationInfo.ts b/react/src/hook/simulationInfo.ts new file mode 100644 index 0000000000..d0819aa7ab --- /dev/null +++ b/react/src/hook/simulationInfo.ts @@ -0,0 +1,7 @@ +import { SimulationInfo } from "../component/simulation"; +import { StoreTypes } from "../data/data"; +import { HandleFactory } from "../data/handle"; + +export function useSimulationInfo(handleFactory: HandleFactory): SimulationInfo { + return handleFactory.createModelHandle("simulation", StoreTypes.Models).hook().value as SimulationInfo; +} diff --git a/react/src/layout/input/enum.tsx b/react/src/layout/input/enum.tsx index ab8af8a87c..bee2a696f4 100644 --- a/react/src/layout/input/enum.tsx +++ b/react/src/layout/input/enum.tsx @@ -1,5 +1,5 @@ import React, { ChangeEventHandler, useContext, useEffect, useState } from "react"; -import { AppWrapper, CAppName, CSimulationInfoPromise } from "../../data/appwrapper"; +import { AppWrapper, CAppName } from "../../data/appwrapper"; import { CRouteHelper } from "../../utility/route"; import { Dependency } from "../../data/dependency"; import { Form } from "react-bootstrap"; @@ -9,6 +9,7 @@ import { LayoutProps } from "../layout"; import { pollStatefulCompute } from "../../utility/compute"; import { CHandleFactory } from "../../data/handle"; import { getValueSelector, StoreType, StoreTypes } from "../../data/data"; +import { useSimulationInfo } from "../../hook/simulationInfo"; export type EnumAllowedValues = { value: string, displayName: string }[] @@ -143,20 +144,20 @@ export class ComputeResultEnumInputLayout extends EnumInputBaseLayout>> = props => { const appName = useContext(CAppName); - const simulationInfoPromise = useContext(CSimulationInfoPromise); + let handleFactory = useContext(CHandleFactory); + let simulationInfo = useSimulationInfo(handleFactory); const routeHelper = useContext(CRouteHelper); const [optionList, updateOptionList] = useState(undefined); useEffect(() => { let enumOptionsPromise = new Promise((resolve, reject) => { - simulationInfoPromise.then(({simulationId, version}) => { - pollStatefulCompute(routeHelper, { - method: this.config.computeMethod, - appName, - simulationId, - callback: respObj => { - resolve(respObj[this.config.resultName]); - } - }) + let { simulationId } = simulationInfo; + pollStatefulCompute(routeHelper, { + method: this.config.computeMethod, + appName, + simulationId, + callback: respObj => { + resolve(respObj[this.config.resultName]); + } }) }) enumOptionsPromise.then(result => updateOptionList( diff --git a/react/src/layout/input/file.tsx b/react/src/layout/input/file.tsx index 83df7724aa..b238221457 100644 --- a/react/src/layout/input/file.tsx +++ b/react/src/layout/input/file.tsx @@ -3,7 +3,7 @@ import * as Icon from "@fortawesome/free-solid-svg-icons"; import React, { ChangeEventHandler, useEffect, useRef } from "react"; import { FunctionComponent, useContext, useState } from "react"; import { Button, Form, Modal } from "react-bootstrap"; -import { CAppName, CSimulationInfoPromise } from "../../data/appwrapper"; +import { CAppName } from "../../data/appwrapper"; import { interpolate } from "../../utility/string"; import { downloadAs } from "../../utility/download"; import { SchemaLayout } from "../../utility/schema"; @@ -14,6 +14,7 @@ import "./file.scss"; import { CRouteHelper } from "../../utility/route"; import { CHandleFactory } from "../../data/handle"; import { StoreTypes } from "../../data/data"; +import { useSimulationInfo } from "../../hook/simulationInfo"; export type FileInputConfig = { pattern: string, @@ -35,8 +36,8 @@ export class FileInputLayout extends InputLayout { let fileListPromise = new Promise((resolve, reject) => { - simulationInfoPromise.then(({ simulationId, version }) => { - fetch(routeHelper.globalRoute("listFiles", { - simulation_type: appName, - simulation_id: "unused", // TODO ??? - file_type: `${dependency.modelName + "-" + dependency.fieldName}?${version}` // TODO ??? - })).then(response => { - if(response.status !== 200) { - reject(); + let { version } = simulationInfo; + fetch(routeHelper.globalRoute("listFiles", { + simulation_type: appName, + simulation_id: "unused", // TODO ??? + file_type: `${dependency.modelName + "-" + dependency.fieldName}?${version}` // TODO ??? + })).then(response => { + if(response.status !== 200) { + reject(); + } + response.json().then(fileNameList => { + // TODO: does this filter need to be here? + if(this.config.pattern) { + fileNameList = (fileNameList || []).filter(fileName => fileName && !!fileName.match(this.config.pattern)); } - response.json().then(fileNameList => { - // TODO: does this filter need to be here? - if(this.config.pattern) { - fileNameList = (fileNameList || []).filter(fileName => fileName && !!fileName.match(this.config.pattern)); - } - resolve(fileNameList); - }) + resolve(fileNameList); }) }) }) @@ -93,16 +93,15 @@ export class FileInputLayout extends InputLayout { - fetch(routeHelper.globalRoute("uploadFile", { - simulation_type: appName, - simulation_id: simulationId, - file_type: dependency.modelName + "-" + dependency.fieldName - }), { - method: 'POST', - body: formData - }).then(resp => updateDummyState({})) - }) + let { simulationId } = simulationInfo; + fetch(routeHelper.globalRoute("uploadFile", { + simulation_type: appName, + simulation_id: simulationId, + file_type: dependency.modelName + "-" + dependency.fieldName + }), { + method: 'POST', + body: formData + }).then(resp => updateDummyState({})) } let downloadFile = () => { diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index a30fd41ca9..67eb6af8c4 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -20,6 +20,8 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; import "./allBeamlineElements.scss"; import "./beamlines.scss"; +import { FormFieldState, FormModelState } from "../../store/formState"; +import { cloneDeep } from "lodash"; export type TemplateSettings = { type: string, @@ -30,6 +32,8 @@ export type TemplateSettings = { export type MadxAllBeamlineElementsConfig = { elementsDependency: string, + selectedBeamlineDependency: string, + beamlinesDependency: string, templateGroups: { name: string, types: string[] @@ -66,7 +70,7 @@ export function MadxBeamlineElementEditor(props: MadxBeamlineElementEditorCommon ) } -export function MadxBeamlineNewElementEditor(props: MadxBeamlineElementEditorCommonProps & { onComplete: (modelState: ModelState, model: string) => void, name: string }) { +export function MadxBeamlineNewElementEditor(props: MadxBeamlineElementEditorCommonProps & { onComplete: (modelState: ModelState, model: string) => void, name: string, id: number }) { let parentHandleFactory = useContext(CHandleFactory); let schema = useContext(CSchema); let store = useStore(); @@ -74,7 +78,7 @@ export function MadxBeamlineNewElementEditor(props: MadxBeamlineElementEditorCom let overridesHandleFactory = new HandleFactoryWithOverrides(schema, [ { fake: props.template.modelName, - value: newModelFromSchema(schema.models[props.template.modelName], { name: props.name }), + value: newModelFromSchema(schema.models[props.template.modelName], { name: props.name, _id: props.id }), onSave: (v) => props.onComplete(v, props.template.modelName) } ], parentHandleFactory); @@ -153,6 +157,9 @@ export class MadxAllBeamlineElementsLayout extends Layout; + let beamlinesHandle = handleFactory.createHandle(new Dependency(this.config.beamlinesDependency), StoreTypes.FormState).hook(); + let beamlinesValue = revertDataStructure(beamlinesHandle.value, getValueSelector(StoreTypes.FormState)) as ArrayFieldState; + let selectedBeamlineHandle = handleFactory.createHandle(new Dependency(this.config.selectedBeamlineDependency), StoreTypes.Models).hook(); let [newElementModalShown, updateNewElementModalShown] = useState(false); let [shownModalTemplate, updateShownModalTemplate] = useState(undefined); @@ -166,9 +173,14 @@ export class MadxAllBeamlineElementsLayout extends Layout { + let _allItems = [...elementsValue, ...beamlinesValue]; + return _allItems.reduce((prev, cur) => Math.max(prev, parseInt((cur.item._id || cur.item.id) as string)), 0); + } + - let addBeamlineElement = (template: TemplateSettings, modelValue: ModelState, model: string) => { + let addNewElement = (template: TemplateSettings, modelValue: ModelState, model: string) => { console.log(`adding beamline element with type=${template.type}`, modelValue); let nv = [...(elementsHandle.value.value as any[])]; @@ -187,13 +199,40 @@ export class MadxAllBeamlineElementsLayout extends Layout { + console.log("adding element", elementId); + let v = cloneDeep(beamlinesHandle.value) as FormFieldState>; + let beamline = v.value.find(b => b.item.id.value == beamlineId); + console.log("before add", beamline.item.items.value); + beamline.item.items.value.push(elementId); + console.log("after add", beamline.item.items.value); + beamlinesHandle.write(v, store.getState(), dispatch); + } - let actionButtons = handleFactory.isDirty() ? : undefined; + let removeElement = (elementId: number | string) => { + let v = cloneDeep(beamlinesHandle.value) as FormFieldState>; + let changed = false; + v.value.forEach(b => { + let idx = b.item.items.value.findIndex(e => e == elementId); + if(idx > 0) { + changed = true; + let v = [...b.item.items.value]; + v.splice(idx, 1); + b.item.items.value = v; + } + }); + if(changed) { + beamlinesHandle.write(v, store.getState(), dispatch); + } + + let nv = [...(elementsHandle.value.value as any[])]; + let idx = nv.findIndex(e => e.item._id.value == elementId); + nv.splice(idx, 1); + elementsHandle.write({ + ...elementsHandle.value, + value: nv + }, store.getState(), dispatch); + } return ( <> @@ -228,14 +267,13 @@ export class MadxAllBeamlineElementsLayout extends Layout { shownModalTemplate && ( - { + { updateShownModalTemplate(undefined); updateNewElementModalShown(false); - }} template={shownModalTemplate} onComplete={(mv, m) => addBeamlineElement(shownModalTemplate, mv, m)}/> + }} template={shownModalTemplate} onComplete={(mv, m) => addNewElement(shownModalTemplate, mv, m)}/> ) }
- {actionButtons}
@@ -278,6 +316,7 @@ export class MadxAllBeamlineElementsLayout extends Layout + {ev.item._id as string} {/*??? TODO: garsuga: where does description come from*/} @@ -290,13 +329,13 @@ export class MadxAllBeamlineElementsLayout extends Layout
- -
@@ -317,7 +356,6 @@ export class MadxAllBeamlineElementsLayout extends Layout - {actionButtons}
diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index 07d615e141..1e98806a30 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -51,6 +51,8 @@ export class MadxBeamlineElementsLayout extends Layout beam.item.id === selectedBeamlineHandle.value).item; + console.log("during update", currentBeamline.items); + console.log("elements during update", _allItems.map(i => i.item.id || i.item._id)) let beamlineElements = (currentBeamline.items as number[]).map(findBeamlineOrElementById) let [shownElement, updateShownElement] = useState<{ diff --git a/react/src/layout/navbar.tsx b/react/src/layout/navbar.tsx index ec5ee9c917..5903763b38 100644 --- a/react/src/layout/navbar.tsx +++ b/react/src/layout/navbar.tsx @@ -10,7 +10,6 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import * as Icon from "@fortawesome/free-solid-svg-icons"; import { CRelativeRouterHelper, RelativeRouteHelper } from "../utility/route"; import React from "react"; -import { CAppWrapper, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; import { Portal } from "../component/reusable/portal"; diff --git a/react/src/layout/panel.tsx b/react/src/layout/panel.tsx index acd465c472..3fc1d24938 100644 --- a/react/src/layout/panel.tsx +++ b/react/src/layout/panel.tsx @@ -5,14 +5,12 @@ import { useDispatch, useStore } from "react-redux"; import { EditorPanel, EditorPanelProps } from "../component/reusable/panel"; import "./panel.scss"; import React from "react"; -import { CAppWrapper, CSimulationInfoPromise } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { LAYOUTS } from "./layouts"; import { useShown } from "../hook/shown"; import { StoreTypes } from "../data/data"; import { CHandleFactory } from "../data/handle"; import { FormStateHandleFactory } from "../data/form"; -import { AnyAction, Dispatch } from "redux"; export type PanelConfig = { basic: SchemaLayout[], diff --git a/react/src/layout/report.tsx b/react/src/layout/report.tsx index a057ac4bf3..82d6bac167 100644 --- a/react/src/layout/report.tsx +++ b/react/src/layout/report.tsx @@ -12,7 +12,7 @@ import { AnimationReader, CReportEventManager, SimulationFrame } from "../data/r import React from "react"; import { CPanelController } from "../data/panel"; import { LAYOUTS } from "./layouts"; -import { CAppName, CSchema, CSimulationInfoPromise } from "../data/appwrapper"; +import { CAppName, CSchema } from "../data/appwrapper"; import { SchemaLayout } from "../utility/schema"; import { CRouteHelper } from "../utility/route"; import { ModelState } from "../store/models"; @@ -20,6 +20,7 @@ import { useShown } from "../hook/shown"; import { CHandleFactory, DependencyReader } from "../data/handle"; import { StoreTypes, ValueSelectors } from "../data/data"; import { interpolate, InterpolationBase } from "../utility/string"; +import { useSimulationInfo } from "../hook/simulationInfo"; export type ReportVisualProps = { data: L, model: ModelState }; @@ -46,10 +47,11 @@ export class AutoRunReportLayout extends Layout { component = (props: LayoutProps<{}>) => { let { dependencies } = this.config; - let simulationInfoPromise = useContext(CSimulationInfoPromise); let appName = useContext(CAppName); let schema = useContext(CSchema); + let store = useStore(); let handleFactory = useContext(CHandleFactory); + let simulationInfo = useSimulationInfo(handleFactory); let routeHelper = useContext(CRouteHelper); let report = interpolate(this.config.report).withDependencies(handleFactory, StoreTypes.Models).raw(); @@ -63,17 +65,16 @@ export class AutoRunReportLayout extends Layout { useEffect(() => { updateSimulationData(undefined); - simulationInfoPromise.then(({ models, simulationId }) => { - pollRunReport(routeHelper, { - appName, - models, - simulationId, - report: report, - forceRun: false, - callback: (simulationData) => { - updateSimulationData(simulationData); - } - }) + let { simulationId } = simulationInfo; + pollRunReport(routeHelper, { + appName, + models: store.getState()[StoreTypes.Models.name], + simulationId, + report: report, + forceRun: false, + callback: (simulationData) => { + updateSimulationData(simulationData); + } }) }, dependentValues) @@ -101,8 +102,8 @@ export function useAnimationReader(reportName: string, reportGroupName: string, } }, [animationReader?.frameCount]) let handleFactory = useContext(CHandleFactory); + let simulationInfo = useSimulationInfo(handleFactory); let reportEventManager = useContext(CReportEventManager); - let simulationInfoPromise = useContext(CSimulationInfoPromise); let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); let reportEventsVersionRef = useRef(uuidv4()) @@ -138,28 +139,27 @@ export function useAnimationReader(reportName: string, reportGroupName: string, }, onReportData: (simulationData: ResponseHasState) => { console.log("onData"); - simulationInfoPromise.then(({models, simulationId}) => { - let { computeJobHash, computeJobSerial } = simulationData; - const s = reportStatus(reportName, simulationData); - if (!animationReader || s.frameCount !== animationReader?.frameCount) { - console.log("frameCount", s.frameCount); - if (s.frameCount > 0) { - let newAnimationReader = new AnimationReader(routeHelper, { - reportName, - simulationId, - appName, - computeJobSerial, - computeJobHash, - frameIdValues: frameIdHandles.map(h => ValueSelectors.Models(h.value)), - frameCount: s.frameCount, - hasAnimationControls: s.hasAnimationControls, - }); - updateAnimationReader(newAnimationReader); - } else { - updateAnimationReader(undefined); - } + let { simulationId } = simulationInfo + let { computeJobHash, computeJobSerial } = simulationData; + const s = reportStatus(reportName, simulationData); + if (!animationReader || s.frameCount !== animationReader?.frameCount) { + console.log("frameCount", s.frameCount); + if (s.frameCount > 0) { + let newAnimationReader = new AnimationReader(routeHelper, { + reportName, + simulationId, + appName, + computeJobSerial, + computeJobHash, + frameIdValues: frameIdHandles.map(h => ValueSelectors.Models(h.value)), + frameCount: s.frameCount, + hasAnimationControls: s.hasAnimationControls, + }); + updateAnimationReader(newAnimationReader); + } else { + updateAnimationReader(undefined); } - }) + } } }) return () => { @@ -324,9 +324,9 @@ export class SimulationStartLayout extends Layout { let reportEventManager = useContext(CReportEventManager); let appName = useContext(CAppName); let routeHelper = useContext(CRouteHelper); - let simulationInfoPromise = useContext(CSimulationInfoPromise); let schema = useContext(CSchema); - let modelNames = Object.keys(schema.models); + let handleFactory = useContext(CHandleFactory); + let simulationInfo = useSimulationInfo(handleFactory); let store = useStore(); @@ -354,28 +354,27 @@ export class SimulationStartLayout extends Layout { useEffect(() => { // recover from previous runs on server - simulationInfoPromise.then(({simulationId}) => { - reportEventManager.getRunStatusOnce({ - appName, - models: store.getState()[StoreTypes.Models.name], - simulationId, - report: reportGroupName - }).then(simulationData => { - // catch running reports after page refresh - updateSimState(simulationData); - if (simulationData.state === 'running') { - listenForReportData(); - reportEventManager.pollRunStatus({ - appName, - models: store.getState()[StoreTypes.Models.name], - simulationId, - report: reportGroupName - }) - } - if (simulationData.elapsedTime) { - stopwatch.setElapsedSeconds(simulationData.elapsedTime); - } - }) + let { simulationId } = simulationInfo; + reportEventManager.getRunStatusOnce({ + appName, + models: store.getState()[StoreTypes.Models.name], + simulationId, + report: reportGroupName + }).then(simulationData => { + // catch running reports after page refresh + updateSimState(simulationData); + if (simulationData.state === 'running') { + listenForReportData(); + reportEventManager.pollRunStatus({ + appName, + models: store.getState()[StoreTypes.Models.name], + simulationId, + report: reportGroupName + }) + } + if (simulationData.elapsedTime) { + stopwatch.setElapsedSeconds(simulationData.elapsedTime); + } }) return () => reportEventManager.clearListenersForKey(simulationPollingVersionRef.current); @@ -385,13 +384,12 @@ export class SimulationStartLayout extends Layout { let startSimulation = () => { listenForReportData(); - simulationInfoPromise.then(({simulationId}) => { - reportEventManager.startReport({ - appName, - models: store.getState()[StoreTypes.Models.name], - simulationId, - report: reportGroupName - }) + let { simulationId } = simulationInfo; + reportEventManager.startReport({ + appName, + models: store.getState()[StoreTypes.Models.name], + simulationId, + report: reportGroupName }) } @@ -400,13 +398,12 @@ export class SimulationStartLayout extends Layout { stopwatch.reset(); simulationPollingVersionRef.current = uuidv4(); - simulationInfoPromise.then(({simulationId}) => { - cancelReport(routeHelper, { - appName, - models: store.getState()[StoreTypes.Models.name], - simulationId, - report: reportGroupName - }) + let { simulationId } = simulationInfo; + cancelReport(routeHelper, { + appName, + models: store.getState()[StoreTypes.Models.name], + simulationId, + report: reportGroupName }) } diff --git a/react/src/layout/shadow/beamline.tsx b/react/src/layout/shadow/beamline.tsx index ccaeb8c759..5d88b3af35 100644 --- a/react/src/layout/shadow/beamline.tsx +++ b/react/src/layout/shadow/beamline.tsx @@ -5,7 +5,7 @@ import { useDispatch, useStore } from "react-redux"; import { formActionFunctions } from "../../component/reusable/form"; import { ViewPanelActionButtons } from "../../component/reusable/panel"; import { ArrayAliases, HandleFactoryWithArrayAliases } from "../../data/alias"; -import { CAppWrapper, CSchema, CSimulationInfoPromise } from "../../data/appwrapper"; +import { CSchema } from "../../data/appwrapper"; import { newModelFromSchema, StoreTypes } from "../../data/data"; import { Dependency } from "../../data/dependency"; import { formStateFromModelState, FormStateHandleFactory } from "../../data/form"; @@ -13,7 +13,7 @@ import { CHandleFactory } from "../../data/handle"; import { ArrayFieldState } from "../../store/common"; import { FormFieldState, FormModelState } from "../../store/formState"; import { CRouteHelper } from "../../utility/route"; -import { Schema, SchemaLayout } from "../../utility/schema"; +import { SchemaLayout } from "../../utility/schema"; import { Layout, LayoutProps } from "../layout"; import { createLayouts } from "../layouts"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; diff --git a/sirepo/package_data/static/react-json/madx-schema.json b/sirepo/package_data/static/react-json/madx-schema.json index 59925c6cc6..f2d69aa163 100644 --- a/sirepo/package_data/static/react-json/madx-schema.json +++ b/sirepo/package_data/static/react-json/madx-schema.json @@ -7599,6 +7599,8 @@ "layout": "madxAllBeamlineElements", "config": { "elementsDependency": "elements.elements", + "beamlinesDependency": "lattice.beamlines", + "selectedBeamlineDependency": "simulation.activeBeamlineId", "templateGroups": [ { "name": "Basic", From 07e57f6e0aba81632167e3ede7571f72d6f222b9 Mon Sep 17 00:00:00 2001 From: garsuga Date: Thu, 18 May 2023 22:34:31 +0000 Subject: [PATCH 50/68] fix child form saving for beamline editor --- react/src/data/form.ts | 1 + react/src/layout/madx/allBeamlineElements.tsx | 40 ++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/react/src/data/form.ts b/react/src/data/form.ts index 44fc14cd90..f99b991ef1 100644 --- a/react/src/data/form.ts +++ b/react/src/data/form.ts @@ -36,6 +36,7 @@ export function initialFormStateFromValue(value: T): FormFieldState { export const callNextParentFunction = (inst: HandleFactory, fnName: 'save' | 'cancel', state: any, dispatch: Dispatch) => { let p = inst.parent; + while(p) { let fn: FormActionFunc = p[fnName]; if(fn) { diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index 67eb6af8c4..4829954a10 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -61,8 +61,14 @@ export function MadxBeamlineElementEditor(props: MadxBeamlineElementEditorCommon { + formHandleFactory.save(store.getState(), store.dispatch); + props.onHide(); + }} + formCancel={() => { + formHandleFactory.cancel(store.getState(), store.dispatch); + props.onHide(); + }} canSave={formHandleFactory.isValid(store.getState())} /> @@ -234,6 +240,11 @@ export class MadxAllBeamlineElementsLayout extends Layout(undefined); + return ( <> updateNewElementModalShown(false)}> @@ -273,6 +284,7 @@ export class MadxAllBeamlineElementsLayout extends Layout addNewElement(shownModalTemplate, mv, m)}/> ) } + {shownElement && updateShownElement(undefined)}/>}
@@ -302,9 +314,19 @@ export class MadxAllBeamlineElementsLayout extends Layout ev.model == category).map((ev: ArrayFieldElement) => { let id = ev.item._id as string; - if(category === "COLLIMATOR") { - console.log(`${category}`, ev.item); - } + let elementsDependency = new Dependency(this.config.elementsDependency); + let template = ev.item.type !== undefined ? getTemplateSettingsByType((ev.item.type as string), this.config.elementTemplates) : undefined; + let aliases: ArrayAliases = ev.item.type !== undefined ? [ + { + realSchemaName: ev.item.type as string, + realDataLocation: { + modelName: elementsDependency.modelName, + fieldName: elementsDependency.fieldName, + index: elementsValue.findIndex(e => e.item._id === id) + }, + fake: ev.item.type as string + } + ] : undefined; return ( hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> @@ -332,7 +354,13 @@ export class MadxAllBeamlineElementsLayout extends Layout addElementToBeamline(id, selectedBeamlineHandle.value as number)}> Add To Beamline - - - + + { + hover.checkHover(id) && ( +
+
+ + + +
-
- ) - } + ) + } + + diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index 1e98806a30..e0b45bcd2d 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -16,6 +16,8 @@ import * as Icon from "@fortawesome/free-solid-svg-icons"; import { LAYOUTS } from "../layouts"; import { ArrayAliases } from "../../data/alias"; import { HoverController } from "../../component/reusable/hover"; +import { FormFieldState, FormModelState } from "../../store/formState"; +import { cloneDeep } from "lodash"; export type MadxBeamlineElmenetsConfig = { selectedBeamlineDependency: string, @@ -51,6 +53,23 @@ export class MadxBeamlineElementsLayout extends Layout beam.item.id === selectedBeamlineHandle.value).item; + let removeElement = (elementId: number | string) => { + let v = cloneDeep(beamlinesHandle.value) as FormFieldState>; + let changed = false; + let b = v.value.find(b => b.item.id.value === selectedBeamlineHandle.value); + console.log("b", b); + let idx = b.item.items.value.findIndex(e => e == elementId); + if(idx > 0) { + changed = true; + let v = [...b.item.items.value]; + v.splice(idx, 1); + b.item.items.value = v; + } + if(changed) { + beamlinesHandle.write(v, store.getState(), dispatch); + } + } + console.log("during update", currentBeamline.items); console.log("elements during update", _allItems.map(i => i.item.id || i.item._id)) let beamlineElements = (currentBeamline.items as number[]).map(findBeamlineOrElementById) @@ -62,7 +81,7 @@ export class MadxBeamlineElementsLayout extends Layout -
+
{ (hover) => { @@ -91,9 +110,9 @@ export class MadxBeamlineElementsLayout extends Layout {`${e.item.name as string}`} -
+
- null}/> + removeElement(id)}/>
diff --git a/react/src/layout/madx/beamlines.scss b/react/src/layout/madx/beamlines.scss index edddf03396..0447ddbe5f 100644 --- a/react/src/layout/madx/beamlines.scss +++ b/react/src/layout/madx/beamlines.scss @@ -1,17 +1,14 @@ .popover-buttons { - flex-flow: row nowrap; - justify-content: flex-end; - display: flex; - align-items: normal; + top: -2px; position: absolute; right: 0px; white-space: nowrap; + display: inline; + float: inline-end; } .popover-buttons-outer { - width: 0; position: relative; - display: inline-block; } .popover-button { @@ -19,6 +16,3 @@ color: white !important; } -table > tr, table > thead, table > tbody { - width: 100%; -} diff --git a/react/src/layout/madx/beamlinesPicker.tsx b/react/src/layout/madx/beamlinesPicker.tsx index 61ab498b85..da2dac2d7a 100644 --- a/react/src/layout/madx/beamlinesPicker.tsx +++ b/react/src/layout/madx/beamlinesPicker.tsx @@ -77,21 +77,19 @@ export class MadxBeamlinesPickerLayout extends Layout {(bl.angle as number).toPrecision(4)} - - { - hover.checkHover(id) && ( -
-
- - + + { + hover.checkHover(id) && ( +
+
+ +
-
- ) - } + ) + } + ) }) From 10922099d783aca641a38f0a8a10199892d65368 Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 23 May 2023 20:44:12 +0000 Subject: [PATCH 52/68] fix row styling --- react/src/layout/madx/allBeamlineElements.tsx | 48 +++++++-------- react/src/layout/madx/beamlines.scss | 6 +- react/src/layout/madx/beamlinesPicker.tsx | 60 +++++++++---------- 3 files changed, 57 insertions(+), 57 deletions(-) diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index 9688d5620c..f5ee9543aa 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -352,33 +352,31 @@ export class MadxAllBeamlineElementsLayout extends Layout {ev.item.angle !== undefined ? `${ev.item.angle}` : ""} - - { - hover.checkHover(id) && ( -
-
- - - -
-
- ) - } - + { + hover.checkHover(id) && ( + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> + + + + + + + ) + } ) diff --git a/react/src/layout/madx/beamlines.scss b/react/src/layout/madx/beamlines.scss index 0447ddbe5f..a70005d76e 100644 --- a/react/src/layout/madx/beamlines.scss +++ b/react/src/layout/madx/beamlines.scss @@ -1,14 +1,16 @@ .popover-buttons { - top: -2px; + bottom: 0; position: absolute; - right: 0px; + right: 5px; white-space: nowrap; display: inline; float: inline-end; + border: none !important; } .popover-buttons-outer { position: relative; + width: 0; } .popover-button { diff --git a/react/src/layout/madx/beamlinesPicker.tsx b/react/src/layout/madx/beamlinesPicker.tsx index da2dac2d7a..d7e5e161cd 100644 --- a/react/src/layout/madx/beamlinesPicker.tsx +++ b/react/src/layout/madx/beamlinesPicker.tsx @@ -59,38 +59,38 @@ export class MadxBeamlinesPickerLayout extends Layout let id = bl.id as number; let isSelected = selectedBeamline === id; return ( - hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)} style={ - { - backgroundColor: isSelected ? "#dff0d8" : undefined, - /*filter: isHovered ? "brightness(75%)" : undefined*/ - } - }> - - {`${name}`} - - - {/* TODO: description */} - - - {(bl.length as number).toPrecision(4)} - - - - {(bl.angle as number).toPrecision(4)} - + <> + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)} style={ { - hover.checkHover(id) && ( -
-
- -
-
- ) + backgroundColor: isSelected ? "#dff0d8" : undefined, + /*filter: isHovered ? "brightness(75%)" : undefined*/ } - - + }> + + {`${name}`} + + + {/* TODO: description */} + + + {(bl.length as number).toPrecision(4)} + + + {(bl.angle as number).toPrecision(4)} + + + { + hover.checkHover(id) && ( + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> + + + + + ) + } + ) }) } From 27d45a17bb404af2f6a6b3223691946f30afbc37 Mon Sep 17 00:00:00 2001 From: garsuga Date: Wed, 24 May 2023 20:11:51 +0000 Subject: [PATCH 53/68] fix shadow beamline scrollbar --- react/src/layout/shadow/beamline.scss | 31 +++++++++++++++++++++++++++ react/src/layout/shadow/beamline.tsx | 6 ++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/react/src/layout/shadow/beamline.scss b/react/src/layout/shadow/beamline.scss index 38463cdb85..dfb6db99ba 100644 --- a/react/src/layout/shadow/beamline.scss +++ b/react/src/layout/shadow/beamline.scss @@ -8,3 +8,34 @@ width: 70px; text-align: center; } + +.beamline { + display: flex; + flex-flow: row nowrap; + max-width: 90%; + overflow: scroll; +} + +.beamline-outer { + display: flex; + flex-flow: row nowrap; + justify-content: center; + width: 100%; +} + +// https://stackoverflow.com/a/61210548 +::-webkit-scrollbar { + height: 8px; + width: 0px; + border: 1px solid #fff; +} + +::-webkit-scrollbar-track { + border-radius: 0; + background: #eeeeee; +} + +::-webkit-scrollbar-thumb { + border-radius: 0; + background: #b0b0b0; +} diff --git a/react/src/layout/shadow/beamline.tsx b/react/src/layout/shadow/beamline.tsx index 5d88b3af35..3b0dfae686 100644 --- a/react/src/layout/shadow/beamline.tsx +++ b/react/src/layout/shadow/beamline.tsx @@ -232,8 +232,10 @@ export class ShadowBeamlineLayout extends Layout {

-
- {beamlineComponents} +
+
+ {beamlineComponents} +
{isDirty && actionButtons} From b81a46b68864ed6652f979b6ed7fdb26255a0c78 Mon Sep 17 00:00:00 2001 From: garsuga Date: Fri, 26 May 2023 21:58:14 +0000 Subject: [PATCH 54/68] move react assets to new folder --- react/public/react/img/sirepo.gif | Bin 833 -> 0 bytes .../react-svg => react/public/svg}/aperture.svg | 0 .../svg/react-svg => react/public/svg}/crl.svg | 0 .../react-svg => react/public/svg}/crystal.svg | 0 .../public/svg}/ellipsoidMirror.svg | 0 .../public/svg}/emptyElement.svg | 0 .../svg/react-svg => react/public/svg}/fiber.svg | 0 .../react-svg => react/public/svg}/grating.svg | 0 .../svg/react-svg => react/public/svg}/lens.svg | 0 .../svg/react-svg => react/public/svg}/mask.svg | 0 .../svg/react-svg => react/public/svg}/mirror.svg | 0 .../react-svg => react/public/svg}/obstacle.svg | 0 .../svg/react-svg => react/public/svg}/sample.svg | 0 .../public/svg}/sphericalMirror.svg | 0 .../public/svg}/toroidalMirror.svg | 0 .../svg/react-svg => react/public/svg}/watch.svg | 0 .../react-svg => react/public/svg}/zonePlate.svg | 0 react/src/component/app.tsx | 4 ---- react/src/component/reusable/navbar.tsx | 2 +- .../static/react-json/common-schema.json | 2 +- 20 files changed, 2 insertions(+), 6 deletions(-) delete mode 100644 react/public/react/img/sirepo.gif rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/aperture.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/crl.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/crystal.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/ellipsoidMirror.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/emptyElement.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/fiber.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/grating.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/lens.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/mask.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/mirror.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/obstacle.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/sample.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/sphericalMirror.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/toroidalMirror.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/watch.svg (100%) rename {sirepo/package_data/static/svg/react-svg => react/public/svg}/zonePlate.svg (100%) diff --git a/react/public/react/img/sirepo.gif b/react/public/react/img/sirepo.gif deleted file mode 100644 index 7d512d0cc8c49674f9832550971b1410aa3c606b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 833 zcmZ?wbhEHbG+@wUI99^I;5U)MZxVz5Bt{UL%os44352FF2ToxLn!*-5l|6VWN61ux zsF{LMGlimOiNwy9NSGs)I8Qoho=oyQ+2nb0Df8ulD0RMi)?$t9#acN_wR4vk7q2ic zUFle}E~sN`aObv!NxPf(*){L8Z`o(p0wNt+_B*tKkYnq9r#29BZav`GcEG9afOFSA zzxD$zUHkmo54d(5bn86m-g(fY3xqs754m?8^5{C`*>%XP8-%=jfatJK&tc!*!+yO- ze0z`h_kmDA|B=A{BSHN~11B5}o_H*D5(tG&2BPB;Q$Q$kDhNeQKNdgrMC8;H(bG=E zOg|Aj{Y2dKlQGjz#!f#OH{)dd%##VTPA1Mgl{o8E(yUX-vrZ??KAke>bn2YbX>-n` z%|Dy9;9Ty)b2$q^WZt54`HRmNF27j5>T>nEtBsp(bp9s-DE?$&u-+MnylqMVfu_V%_)=nl;jm>E~;0Vqtzq9&B(;aBD#3G z>m0K-VOF*sJJ}ZH#%1@L=xA+emE3ilbB58J4Nc6)kIPN4TV}sOgz3UAu?eT=SZv_C zwM*dcvLlOlAMX^J5UVjoEog)E&DY}7lhu?}6VKN3Ut|68o&SIZAIt2<1P6t1MixOK zp*IT>4lwcx8E4&z(BM6u7VkF0!ElkQj8pNIJwG!t+E;oeu?TuLGR+g4*3^?zHS`a+lP zUk>%~6gTzd2N^v`mfnzJfJrmi$l$gQ(v37fLgMNc$U#r5L}oi-l>*J4f108u9% z-Ac(N7qWs)jg}fdQaa(~?CM{j$?{}#*Ji1?5zCM45D=D)m{oJ;;Fc|M2DjBEFIt~C Y<}Lh&GtxX!%}!C#t!II<1P6mP0F?cNn*aa+ diff --git a/sirepo/package_data/static/svg/react-svg/aperture.svg b/react/public/svg/aperture.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/aperture.svg rename to react/public/svg/aperture.svg diff --git a/sirepo/package_data/static/svg/react-svg/crl.svg b/react/public/svg/crl.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/crl.svg rename to react/public/svg/crl.svg diff --git a/sirepo/package_data/static/svg/react-svg/crystal.svg b/react/public/svg/crystal.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/crystal.svg rename to react/public/svg/crystal.svg diff --git a/sirepo/package_data/static/svg/react-svg/ellipsoidMirror.svg b/react/public/svg/ellipsoidMirror.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/ellipsoidMirror.svg rename to react/public/svg/ellipsoidMirror.svg diff --git a/sirepo/package_data/static/svg/react-svg/emptyElement.svg b/react/public/svg/emptyElement.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/emptyElement.svg rename to react/public/svg/emptyElement.svg diff --git a/sirepo/package_data/static/svg/react-svg/fiber.svg b/react/public/svg/fiber.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/fiber.svg rename to react/public/svg/fiber.svg diff --git a/sirepo/package_data/static/svg/react-svg/grating.svg b/react/public/svg/grating.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/grating.svg rename to react/public/svg/grating.svg diff --git a/sirepo/package_data/static/svg/react-svg/lens.svg b/react/public/svg/lens.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/lens.svg rename to react/public/svg/lens.svg diff --git a/sirepo/package_data/static/svg/react-svg/mask.svg b/react/public/svg/mask.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/mask.svg rename to react/public/svg/mask.svg diff --git a/sirepo/package_data/static/svg/react-svg/mirror.svg b/react/public/svg/mirror.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/mirror.svg rename to react/public/svg/mirror.svg diff --git a/sirepo/package_data/static/svg/react-svg/obstacle.svg b/react/public/svg/obstacle.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/obstacle.svg rename to react/public/svg/obstacle.svg diff --git a/sirepo/package_data/static/svg/react-svg/sample.svg b/react/public/svg/sample.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/sample.svg rename to react/public/svg/sample.svg diff --git a/sirepo/package_data/static/svg/react-svg/sphericalMirror.svg b/react/public/svg/sphericalMirror.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/sphericalMirror.svg rename to react/public/svg/sphericalMirror.svg diff --git a/sirepo/package_data/static/svg/react-svg/toroidalMirror.svg b/react/public/svg/toroidalMirror.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/toroidalMirror.svg rename to react/public/svg/toroidalMirror.svg diff --git a/sirepo/package_data/static/svg/react-svg/watch.svg b/react/public/svg/watch.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/watch.svg rename to react/public/svg/watch.svg diff --git a/sirepo/package_data/static/svg/react-svg/zonePlate.svg b/react/public/svg/zonePlate.svg similarity index 100% rename from sirepo/package_data/static/svg/react-svg/zonePlate.svg rename to react/public/svg/zonePlate.svg diff --git a/react/src/component/app.tsx b/react/src/component/app.tsx index f03e1d48ef..f8359adcc1 100644 --- a/react/src/component/app.tsx +++ b/react/src/component/app.tsx @@ -1,9 +1,5 @@ import React, { useContext, useEffect } from "react"; -import { configureStore } from "@reduxjs/toolkit" -import { modelsSlice } from "../store/models"; -import { formStatesSlice } from "../store/formState"; import { useSetup } from "../hook/setup"; -import { Provider } from "react-redux"; import { SimulationBrowserRoot } from "./simbrowser"; import "./app.scss"; import { AppWrapper, CAppName, CAppWrapper, CSchema, CSimulationList } from "../data/appwrapper"; diff --git a/react/src/component/reusable/navbar.tsx b/react/src/component/reusable/navbar.tsx index 8eaba7ddfe..a1b7ded6e2 100644 --- a/react/src/component/reusable/navbar.tsx +++ b/react/src/component/reusable/navbar.tsx @@ -24,7 +24,7 @@ export function SrNavbar(props) { Date: Mon, 29 May 2023 19:05:02 +0000 Subject: [PATCH 55/68] fix use index for deleting beamline elements, remove description --- react/src/layout/madx/allBeamlineElements.tsx | 9 +++--- react/src/layout/madx/beamlineElements.tsx | 29 +++++++------------ react/src/layout/madx/beamlinesPicker.tsx | 10 +++---- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index f5ee9543aa..d694158aed 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -299,7 +299,7 @@ export class MadxAllBeamlineElementsLayout extends Layout Name - Description + {/*Description*/} Length Bend @@ -343,10 +343,9 @@ export class MadxAllBeamlineElementsLayout extends Layout - - {ev.item._id as string} - {/*??? TODO: garsuga: where does description come from*/} - + {/* + {??? TODO: garsuga: where does description come from} + */} {ev.item.l !== undefined ? `${(ev.item.l)}m` : ""} diff --git a/react/src/layout/madx/beamlineElements.tsx b/react/src/layout/madx/beamlineElements.tsx index e0b45bcd2d..a1bc5b2ada 100644 --- a/react/src/layout/madx/beamlineElements.tsx +++ b/react/src/layout/madx/beamlineElements.tsx @@ -53,21 +53,14 @@ export class MadxBeamlineElementsLayout extends Layout beam.item.id === selectedBeamlineHandle.value).item; - let removeElement = (elementId: number | string) => { - let v = cloneDeep(beamlinesHandle.value) as FormFieldState>; - let changed = false; - let b = v.value.find(b => b.item.id.value === selectedBeamlineHandle.value); + let removeElement = (index: number) => { + let bv = cloneDeep(beamlinesHandle.value) as FormFieldState>; + let b = bv.value.find(b => b.item.id.value === selectedBeamlineHandle.value); console.log("b", b); - let idx = b.item.items.value.findIndex(e => e == elementId); - if(idx > 0) { - changed = true; - let v = [...b.item.items.value]; - v.splice(idx, 1); - b.item.items.value = v; - } - if(changed) { - beamlinesHandle.write(v, store.getState(), dispatch); - } + let v = [...b.item.items.value]; + v.splice(index, 1); + b.item.items.value = v; + beamlinesHandle.write(bv, store.getState(), dispatch); } console.log("during update", currentBeamline.items); @@ -85,7 +78,7 @@ export class MadxBeamlineElementsLayout extends Layout { (hover) => { - return beamlineElements.map(e => { + return beamlineElements.map((e, idx) => { let id = (e.item._id !== undefined ? e.item._id : e.item.id) as number; let template = e.item.type !== undefined ? getTemplateSettingsByType((e.item.type as string), this.config.elementTemplates) : undefined; let aliases: ArrayAliases = e.item.type !== undefined ? [ @@ -100,7 +93,7 @@ export class MadxBeamlineElementsLayout extends Layout hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> +
hover.aquireHover(idx)} onMouseLeave={() => hover.releaseHover(idx)}> { updateShownElement({ template, @@ -111,8 +104,8 @@ export class MadxBeamlineElementsLayout extends Layout
-
- removeElement(id)}/> +
+ removeElement(idx)}/>
diff --git a/react/src/layout/madx/beamlinesPicker.tsx b/react/src/layout/madx/beamlinesPicker.tsx index d7e5e161cd..3c6f2ddcd2 100644 --- a/react/src/layout/madx/beamlinesPicker.tsx +++ b/react/src/layout/madx/beamlinesPicker.tsx @@ -39,9 +39,9 @@ export class MadxBeamlinesPickerLayout extends Layout Name - + {/* Description - + */} Length @@ -69,9 +69,9 @@ export class MadxBeamlinesPickerLayout extends Layout {`${name}`} - - {/* TODO: description */} - + {/* + TODO: description + */} {(bl.length as number).toPrecision(4)} From 94b251316cd5a8c6d6d1e4735adb1df6e576986a Mon Sep 17 00:00:00 2001 From: garsuga Date: Tue, 30 May 2023 20:46:06 +0000 Subject: [PATCH 56/68] add element descriptions --- react/src/layout/madx/allBeamlineElements.tsx | 194 ++++++++++-------- react/src/layout/madx/beamlines.scss | 16 ++ 2 files changed, 119 insertions(+), 91 deletions(-) diff --git a/react/src/layout/madx/allBeamlineElements.tsx b/react/src/layout/madx/allBeamlineElements.tsx index d694158aed..dd274c68c6 100644 --- a/react/src/layout/madx/allBeamlineElements.tsx +++ b/react/src/layout/madx/allBeamlineElements.tsx @@ -22,6 +22,7 @@ import "./allBeamlineElements.scss"; import "./beamlines.scss"; import { FormFieldState, FormModelState } from "../../store/formState"; import { cloneDeep } from "lodash"; +import { SchemaModel } from "../../utility/schema"; export type TemplateSettings = { type: string, @@ -153,6 +154,13 @@ export function getTemplateSettingsByType(type: string, templates: TemplateSetti return ret; } +function getElementDescription(element: ModelState, modelSchema: SchemaModel): string { + return Object.entries(element).filter(([name, ]) => !(name == 'name' || name == 'l' || name == 'angle')) + .sort(([a, ], [b, ]) => a.localeCompare(b)) + .filter(([name, value]) => name in modelSchema && value !== modelSchema[name].defaultValue) + .map(([name, value]) => `${name}=${value}`).join(", "); +} + export class MadxAllBeamlineElementsLayout extends Layout { constructor(config: MadxAllBeamlineElementsConfig) { super(config); @@ -163,6 +171,7 @@ export class MadxAllBeamlineElementsLayout extends Layout; @@ -295,100 +304,103 @@ export class MadxAllBeamlineElementsLayout extends Layout
- - - - - {/**/} - - - - - - { - (hover) => { - return [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { - return ( - - - - - { - elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { - let id = ev.item._id as string; - let elementsDependency = new Dependency(this.config.elementsDependency); - let template = ev.item.type !== undefined ? getTemplateSettingsByType((ev.item.type as string), this.config.elementTemplates) : undefined; - let aliases: ArrayAliases = ev.item.type !== undefined ? [ - { - realSchemaName: ev.item.type as string, - realDataLocation: { - modelName: elementsDependency.modelName, - fieldName: elementsDependency.fieldName, - index: elementsValue.findIndex(e => e.item._id === id) - }, - fake: ev.item.type as string - } - ] : undefined; - return ( - - hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> - - {/**/} - - - +
+
NameDescriptionLengthBend
- - {category} - -
-
- - {ev.item.name as string} - -
-
- {??? TODO: garsuga: where does description come from} - - {ev.item.l !== undefined ? `${(ev.item.l)}m` : ""} - - {ev.item.angle !== undefined ? `${ev.item.angle}` : ""} -
+ + + + + + + + + + { + (hover) => { + return [...new Set(elementsValue.map((ev: ArrayFieldElement) => ev.model))].sort((a: string, b: string) => a.localeCompare(b)).map((category: string) => { + return ( + + + + + { + elementsValue.filter(ev => ev.model == category).map((ev: ArrayFieldElement) => { + let id = ev.item._id as string; + let description = getElementDescription(ev.item, schema.models[ev.model]); + let elementsDependency = new Dependency(this.config.elementsDependency); + let template = ev.item.type !== undefined ? getTemplateSettingsByType((ev.item.type as string), this.config.elementTemplates) : undefined; + let aliases: ArrayAliases = ev.item.type !== undefined ? [ { - hover.checkHover(id) && ( - hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> - - - ) + realSchemaName: ev.item.type as string, + realDataLocation: { + modelName: elementsDependency.modelName, + fieldName: elementsDependency.fieldName, + index: elementsValue.findIndex(e => e.item._id === id) + }, + fake: ev.item.type as string } - - - ) - }) - } - - ) - - }) + ] : undefined; + return ( + + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> + + + + + + { + hover.checkHover(id) && ( + hover.aquireHover(id)} onMouseLeave={() => hover.releaseHover(id)}> + + + ) + } + + + ) + }) + } + + ) + + }) + } } - } - -
NameDescriptionLengthBend
+ + {category} + +
- - - -
+
+ + {ev.item.name as string} + +
+
+ {description} + + {ev.item.l !== undefined ? `${(ev.item.l)}m` : ""} + + {ev.item.angle !== undefined ? `${ev.item.angle}` : ""} +
+ + + +
+ + +
diff --git a/react/src/layout/madx/beamlines.scss b/react/src/layout/madx/beamlines.scss index a70005d76e..1db402dd2f 100644 --- a/react/src/layout/madx/beamlines.scss +++ b/react/src/layout/madx/beamlines.scss @@ -18,3 +18,19 @@ color: white !important; } +.table-text { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + width: 100%; + display: inline-block; +} + +.table-cell { + overflow: hidden; +} + +table { + width: 100%; + table-layout: fixed; +} From eac91bb587c36f25241a6d4038a704b89948da09 Mon Sep 17 00:00:00 2001 From: moellep Date: Tue, 30 May 2023 21:13:25 +0000 Subject: [PATCH 57/68] for #5914 reverse shadow server changes --- sirepo/pkcli/shadow.py | 11 +-- sirepo/sim_data/shadow.py | 113 ++++++++++------------------- sirepo/template/shadow.py | 28 +++---- sirepo/template/template_common.py | 4 +- 4 files changed, 51 insertions(+), 105 deletions(-) diff --git a/sirepo/pkcli/shadow.py b/sirepo/pkcli/shadow.py index 6846b43ad4..940ddd7bb8 100644 --- a/sirepo/pkcli/shadow.py +++ b/sirepo/pkcli/shadow.py @@ -10,14 +10,11 @@ from pykern.pkdebug import pkdp, pkdlog, pkdexc from sirepo import simulation_db from sirepo.template import template_common -import sirepo.sim_data import numpy import py.path import re import sirepo.template.shadow as template -_SIM_DATA, _, _ = sirepo.sim_data.template_globals() - _MM_TO_CM = 0.1 _CM_TO_M = 0.01 _SCHEMA = simulation_db.get_schema(template.SIM_TYPE) @@ -122,13 +119,7 @@ def _run_beam_statistics(cfg_dir, data): def _run_shadow(cfg_dir, data): beam = template_common.exec_parameters().beam - r = data["report"] - model = None - if _SIM_DATA.is_watchpoint(r): - i = _SIM_DATA.watchpoint_id(r) - model = data["models"]["watchpointReports"]["reports"][i].item - else: - model = data["models"][data["report"]] + model = data["models"][data["report"]] column_values = _SCHEMA["enum"]["ColumnValue"] if "y" in model: diff --git a/sirepo/sim_data/shadow.py b/sirepo/sim_data/shadow.py index 661abc3c53..7a7f714b08 100644 --- a/sirepo/sim_data/shadow.py +++ b/sirepo/sim_data/shadow.py @@ -7,74 +7,18 @@ from __future__ import absolute_import, division, print_function from pykern.pkcollections import PKDict from pykern.pkdebug import pkdc, pkdlog, pkdp -from pykern import pkconfig -from pykern import pkjson import sirepo.sim_data import scipy.constants -import hashlib class SimData(sirepo.sim_data.SimDataBase): ANALYSIS_ONLY_FIELDS = frozenset(("colorMap", "notes", "aspectRatio")) - @classmethod - def compute_job_hash(cls, data, qcall): - """Hash fields related to data and set computeJobHash - - Only needs to be unique relative to the report, not globally unique - so MD5 is adequate. Long and cryptographic hashes make the - cache checks slower. - - Args: - data (dict): simulation data - changed (callable): called when value changed - Returns: - bytes: hash value - """ - cls._assert_server_side() - c = cls.compute_model(data) - if data.get("forceRun") or cls.is_parallel(c): - return "HashIsUnused" - m = data["models"] - res = hashlib.md5() - fields = sirepo.sim_data.get_class(data.simulationType)._compute_job_fields( - data, data.report, c - ) - # values may be string or PKDict - fields.sort(key=lambda x: str(x)) - for f in fields: - # assert isinstance(f, pkconfig.STRING_TYPES), \ - # 'value={} not a string_type'.format(f) - # TODO(pjm): work-around for now - if isinstance(f, pkconfig.STRING_TYPES): - x = f.split(".") - if cls.is_watchpoint(f) and f != "watchpointReports": - i = cls.watchpoint_id(f) - value = m.watchpointReports.reports[i].item - else: - value = m[x[0]][x[1]] if len(x) > 1 else m[x[0]] - else: - value = f - res.update( - pkjson.dump_bytes( - value, - sort_keys=True, - allow_nan=False, - ) - ) - res.update( - "".join( - ( - str(cls.lib_file_abspath(b, data=data, qcall=qcall).mtime()) - for b in sorted(cls.lib_file_basenames(data)) - ), - ).encode() - ) - return res.hexdigest() - @classmethod def fixup_old_data(cls, data, qcall, **kwargs): dm = data.models + if not isinstance(dm.beamline, list): + raise AssertionError("models.beamline is in the incorrect format") cls._init_models( dm, ( @@ -94,12 +38,22 @@ def fixup_old_data(cls, data, qcall, **kwargs): * float(dm.electronBeam.bener) / float(dm.bendingMagnet.r_magnet) ) - if isinstance(dm.beamline, list): - dm.beamline = PKDict( - elements=list(map(lambda i: PKDict(model=i.type, item=i), dm.beamline)) - ) - if not "watchpointReports" in dm: - dm.watchpointReports = PKDict(reports=[]) + for m in dm: + if cls.is_watchpoint(m): + cls.update_model_defaults(dm[m], "watchpointReport") + for m in dm.beamline: + cls.update_model_defaults(m, m.type) + cls._organize_example(data) + + @classmethod + def react_format_data(cls, data): + dm = data.models + assert isinstance(dm.beamline, list) + dm.beamline = PKDict( + elements=list(map(lambda i: PKDict(model=i.type, item=i), dm.beamline)) + ) + assert not dm.get("watchpointReports") + dm.watchpointReports = PKDict(reports=[]) n = [] for m in dm: if cls.is_watchpoint(m) and m != "watchpointReports": @@ -112,9 +66,24 @@ def fixup_old_data(cls, data, qcall, **kwargs): n.append(m) for i in n: del dm[i] - for m in map(lambda i: i.item, dm.beamline.elements): - cls.update_model_defaults(m, m.type) - cls._organize_example(data) + + @classmethod + def react_unformat_data(cls, data): + dm = data.models + # assert not isinstance(dm.beamline, list) + if isinstance(dm.beamline, list): + return + dm.beamline = [e.item for e in dm.beamline.elements] + assert "watchpointReports" in dm + names = [] + for r in dm.watchpointReports.reports: + n = f"watchpointReport{r.item.id}" + assert not dm.get(n) + dm[n] = r.item + names.append(n) + del dm["watchpointReports"] + if data.get("report") and cls.is_watchpoint(data.report): + data.report = names[cls.watchpoint_id(data.report)] @classmethod def shadow_simulation_files(cls, data): @@ -129,6 +98,7 @@ def shadow_wiggler_file(cls, value): @classmethod def _compute_job_fields(cls, data, r, compute_model): + assert r in data.models res = cls._non_analysis_fields(data, r) + [ "bendingMagnet", "electronBeam", @@ -142,13 +112,8 @@ def _compute_job_fields(cls, data, r, compute_model): "undulatorBeam", "wiggler", ] - if ( - r == "initialIntensityReport" - and data["models"]["beamline"] - and data["models"]["beamline"]["elements"] - and len(data["models"]["beamline"]["elements"]) > 0 - ): - res.append([data["models"]["beamline"]["elements"][0]["item"]["position"]]) + if r == "initialIntensityReport" and data["models"]["beamline"]: + res.append([data["models"]["beamline"][0]["position"]]) # TODO(pjm): only include items up to the current watchpoint if cls.is_watchpoint(r) or r == "beamStatisticsReport": res.append("beamline") diff --git a/sirepo/template/shadow.py b/sirepo/template/shadow.py index 771f553907..b9c44bdf78 100644 --- a/sirepo/template/shadow.py +++ b/sirepo/template/shadow.py @@ -182,20 +182,14 @@ def post_execution_processing(success_exit, is_parallel, run_dir, **kwargs): def python_source_for_model(data, model, qcall, **kwargs): data.report = model if not model: - beamline = list(map(lambda i: i.item, data.models.beamline.elements)) + beamline = data.models.beamline watch_id = None watch_index = None for b in beamline: if b.type == "watch": watch_id = b.id if watch_id: - for i, w in enumerate(data.models.watchpointReports.reports): - if w.item.id == watch_id: - watch_index = i - if watch_index: - data.report = "{}{}".format(_SIM_DATA.WATCHPOINT_REPORT, watch_index) - else: - data.report = "plotXYReport" + data.report = "{}{}".format(_SIM_DATA.WATCHPOINT_REPORT, watch_id) else: data.report = "plotXYReport" return """ @@ -295,7 +289,7 @@ def _generate_autotune_element(item): def _generate_beamline_optics(models, last_id=None, calc_beam_stats=False): - beamline = list(map(lambda i: i.item, models.beamline.elements)) + beamline = models.beamline res = "" prev_position = source_position = 0 last_element = False @@ -730,9 +724,8 @@ def _generate_parameters_file(data, run_dir=None, is_parallel=False): _scale_units(data) v = template_common.flatten_data(data.models, PKDict()) r = data.report - - # report_model = data.models[r] - beamline = list(map(lambda i: i.item, data.models.beamline.elements)) + report_model = data.models[r] + beamline = data.models.beamline v.shadowOutputFile = _SHADOW_OUTPUT_FILE if _has_zone_plate(beamline): v.zonePlateMethods = template_common.render_jinja(SIM_TYPE, v, "zone_plate.py") @@ -781,11 +774,11 @@ def _generate_parameters_file(data, run_dir=None, is_parallel=False): v.photonEnergy = v.bendingMagnet_ph1 return template_common.render_jinja(SIM_TYPE, v, "beam_statistics.py") elif _SIM_DATA.is_watchpoint(r): - di = _SIM_DATA.watchpoint_id(r) - rd = data.models.watchpointReports.reports[di] - v.beamlineOptics = _generate_beamline_optics(data.models, last_id=rd.item.id) + v.beamlineOptics = _generate_beamline_optics( + data.models, last_id=_SIM_DATA.watchpoint_id(r) + ) else: - v.distanceFromSource = data.models[r].distanceFromSource + v.distanceFromSource = report_model.distanceFromSource return template_common.render_jinja(SIM_TYPE, v) @@ -952,7 +945,6 @@ def _item_field(item, fields): def _parse_shadow_log(run_dir): if run_dir.join(template_common.RUN_LOG).exists(): text = pkio.read_text(run_dir.join(template_common.RUN_LOG)) - pkdp(text) for line in text.split("\n"): if re.search(r"invalid chemical formula", line): return "A mirror contains an invalid reflectivity material" @@ -978,7 +970,7 @@ def _scale_units(data): for name in _MODEL_UNITS.unit_def: if name in data.models: _MODEL_UNITS.scale_to_native(name, data.models[name]) - for item in list(map(lambda i: i.item, data.models.beamline.elements)): + for item in data.models.beamline: if item.type in _MODEL_UNITS.unit_def: _MODEL_UNITS.scale_to_native(item.type, item) diff --git a/sirepo/template/template_common.py b/sirepo/template/template_common.py index 6181ed5409..8c62d93d4a 100644 --- a/sirepo/template/template_common.py +++ b/sirepo/template/template_common.py @@ -825,9 +825,7 @@ def validate_models(model_data, model_schema): enum_info, ) if "beamline" in model_data["models"]: - for m in model_data["models"]["beamline"]["elements"]: - if isinstance(m, PKDict): - m = m.item + for m in model_data["models"]["beamline"]: validate_model(m, model_schema["model"][m["type"]], enum_info) return enum_info From 2840008784e743fb48e684e00149fd6ccb489c10 Mon Sep 17 00:00:00 2001 From: moellep Date: Tue, 30 May 2023 21:48:10 +0000 Subject: [PATCH 58/68] for #5914 react/shadow data format/unformat unformat react data - simulation_db.fixup_old_data() - job_api._request_content() format react data - server.API._simulation_data_reply() --- sirepo/feature_config.py | 4 ++++ sirepo/job_api.py | 5 +++++ sirepo/server.py | 2 ++ sirepo/sim_data/__init__.py | 8 ++++++++ sirepo/simulation_db.py | 5 ++++- 5 files changed, 23 insertions(+), 1 deletion(-) diff --git a/sirepo/feature_config.py b/sirepo/feature_config.py index 7c8308421e..024969cfa2 100644 --- a/sirepo/feature_config.py +++ b/sirepo/feature_config.py @@ -96,6 +96,10 @@ def for_sim_type(sim_type): ) +def is_react_sim_type(sim_type): + return sim_type in cfg().react_sim_types + + def proprietary_sim_types(): """All sim types that have proprietary information and require granted access to use diff --git a/sirepo/job_api.py b/sirepo/job_api.py index 9d70f7cf56..d264d9fbc4 100644 --- a/sirepo/job_api.py +++ b/sirepo/job_api.py @@ -15,6 +15,7 @@ import pykern.pkio import re import sirepo.auth +import sirepo.feature_config import sirepo.flask import sirepo.job import sirepo.quest @@ -324,6 +325,10 @@ def _request_content(self, kwargs): check_sim_exists=True, ).req_data s = sirepo.sim_data.get_class(d) + if sirepo.feature_config.is_react_sim_type(s.sim_type()): + # TODO(pjm): need to know if this is the full sirepo data + if d.get("models"): + s.react_unformat_data(d) ##TODO(robnagler) this should be req_data b = PKDict(data=d, **kwargs) # TODO(e-carlin): some of these fields are only used for some type of reqs diff --git a/sirepo/server.py b/sirepo/server.py index 2b5de5560d..58ee4703f1 100644 --- a/sirepo/server.py +++ b/sirepo/server.py @@ -779,6 +779,8 @@ def _save_new_and_reply(self, req, data): def _simulation_data_reply(self, req, data): if hasattr(req.template, "prepare_for_client"): d = req.template.prepare_for_client(data, qcall=self) + if sirepo.feature_config.is_react_sim_type(req.type): + req.sim_data.react_format_data(data) return self.headers_for_no_cache(self.reply_json(data)) diff --git a/sirepo/sim_data/__init__.py b/sirepo/sim_data/__init__.py index 61275e7880..ea7500a3a4 100644 --- a/sirepo/sim_data/__init__.py +++ b/sirepo/sim_data/__init__.py @@ -273,6 +273,14 @@ def fixup_old_data(cls, data, qcall, **kwargs): """ raise NotImplementedError() + @classmethod + def react_format_data(cls, data): + pass + + @classmethod + def react_unformat_data(cls, data): + pass + @classmethod def frame_id(cls, data, response, model, index): """Generate a frame_id from values (unit testing) diff --git a/sirepo/simulation_db.py b/sirepo/simulation_db.py index 79fe469953..f8953d0e6a 100644 --- a/sirepo/simulation_db.py +++ b/sirepo/simulation_db.py @@ -249,7 +249,10 @@ def _last_modified(data, path): data.models.simulation.lastModified = _last_modified(data, path) from sirepo import sim_data - sim_data.get_class(data.simulationType).fixup_old_data(data, qcall=qcall) + s = sim_data.get_class(data.simulationType) + if sirepo.feature_config.is_react_sim_type(s.sim_type()): + s.react_unformat_data(data) + s.fixup_old_data(data, qcall=qcall) data.pkdel("fixup_old_version") return data, True except Exception as e: From 1b0c66f1ca0ab9a0976753685e223d2b9a681ec8 Mon Sep 17 00:00:00 2001 From: moellep Date: Wed, 31 May 2023 16:46:15 +0000 Subject: [PATCH 59/68] for #5914 madx to/from react format --- sirepo/server.py | 4 ++++ sirepo/sim_data/madx.py | 33 +++++++++++++++++++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/sirepo/server.py b/sirepo/server.py index 58ee4703f1..33b0108e1a 100644 --- a/sirepo/server.py +++ b/sirepo/server.py @@ -778,6 +778,10 @@ def _save_new_and_reply(self, req, data): def _simulation_data_reply(self, req, data): if hasattr(req.template, "prepare_for_client"): + # TODO(pjm): for some reason _simulation_data_reply() can be called twice in one request + # see madx FODO PTC example + if sirepo.feature_config.is_react_sim_type(req.type): + req.sim_data.react_unformat_data(data) d = req.template.prepare_for_client(data, qcall=self) if sirepo.feature_config.is_react_sim_type(req.type): req.sim_data.react_format_data(data) diff --git a/sirepo/sim_data/madx.py b/sirepo/sim_data/madx.py index 7a5041d6dc..6524d3a2c5 100644 --- a/sirepo/sim_data/madx.py +++ b/sirepo/sim_data/madx.py @@ -25,18 +25,35 @@ def fixup_old_data(cls, data, qcall, **kwargs): ) for container in ("commands", "elements"): for m in dm[container]: - if not isinstance(m, list): - continue cls.update_model_defaults(m, LatticeUtil.model_name_for_data(m)) - if "beamlines" in dm and isinstance(dm.beamlines, list): + + @classmethod + def react_format_data(cls, data): + pkdp("madx format data") + dm = data.models + if "beamlines" in dm: + assert isinstance(dm.beamlines, list) dm.lattice = PKDict( - beamlines=list(map(lambda i: PKDict(model="Beamline", item=i), dm.beamlines)) + beamlines=list( + map(lambda i: PKDict(model="Beamline", item=i), dm.beamlines) + ) ) del dm["beamlines"] + assert isinstance(dm.elements, list) + dm.elements = PKDict( + elements=list(map(lambda i: PKDict(model=i.type, item=i), dm.elements)) + ) + + @classmethod + def react_unformat_data(cls, data): + pkdp("madx unformat data") + dm = data.models if isinstance(dm.elements, list): - dm.elements = PKDict( - elements=list(map(lambda i: PKDict(model=i.type, item=i), dm.elements)) - ) + return + if "lattice" in dm: + dm.beamlines = [i.item for i in dm.lattice.beamlines] + del dm["lattice"] + dm.elements = [i.item for i in dm.elements.elements] @classmethod def _compute_job_fields(cls, data, r, compute_model): @@ -50,7 +67,7 @@ def _compute_job_fields(cls, data, r, compute_model): ] if r == "twissReport": res += [ - "lattice", + "beamlines", "elements", "simulation.activeBeamlineId", "rpnVariables", From da5336c70b08534a1cc075778c8049803ee630f0 Mon Sep 17 00:00:00 2001 From: moellep Date: Wed, 31 May 2023 16:46:40 +0000 Subject: [PATCH 60/68] for #5914 revert madx server --- sirepo/template/code_variable.py | 2 +- sirepo/template/lattice.py | 77 ++++++++++++------------------- sirepo/template/madx.py | 46 ++++++++---------- sirepo/template/madx_converter.py | 18 +++----- sirepo/template/madx_parser.py | 8 +--- sirepo/template/shadow.py | 1 - 6 files changed, 58 insertions(+), 94 deletions(-) diff --git a/sirepo/template/code_variable.py b/sirepo/template/code_variable.py index 59ad73f839..9fbf542cbf 100644 --- a/sirepo/template/code_variable.py +++ b/sirepo/template/code_variable.py @@ -281,7 +281,7 @@ def __add_beamline_fields(self, data, schema): if not schema.get("model") or not schema.model.get("beamline"): return bs = schema.model.beamline - for bl in map(lambda i: i.item, data.models.lattice.beamlines): + for bl in data.models.beamlines: if "positions" not in bl: continue for f in bs: diff --git a/sirepo/template/lattice.py b/sirepo/template/lattice.py index 60bf590c35..f0f40c1ac1 100644 --- a/sirepo/template/lattice.py +++ b/sirepo/template/lattice.py @@ -175,13 +175,13 @@ def _fix_value(value, names): for v in self.data.models.rpnVariables: if CodeVar.is_var_value(v.value): v.value = _fix_value(v.value, names) - for el in map(lambda i: i.item, self.data.models.elements.elements): + for el in self.data.models.elements: for f in el: v = el[f] if CodeVar.is_var_value(v): el[f] = _fix_value(v, names) for name in names: - for el in map(lambda i: i.item, self.data.models.elements.elements): + for el in self.data.models.elements: if el.name.lower() == names[name][0]: f = names[name][1] if f in el: @@ -206,7 +206,7 @@ def _float_update(model, field): def _compute_drifts(self, code_var): drifts = PKDict() - for el in map(lambda i: i.item, self.data.models.elements.elements): + for el in self.data.models.elements: if el.type == "DRIFT": length = self._format_length(self._eval_var(code_var, el.l)) if length not in drifts: @@ -257,10 +257,7 @@ def _get_drift(self, drifts, length, allow_negative_drift=False): type="DRIFT", ) self.sim_data.update_model_defaults(drift, "DRIFT") - self.data.models.elements.elements.append(PKDict( - model="DRIFT", - item=drift - )) + self.data.models.elements.append(drift) drifts[length] = drift._id return drifts[length] @@ -280,8 +277,8 @@ def _set_default_beamline(self, cmd_type, field1, field2=None): beamline_id = None if name: beamline_id = self.elements_by_name[name].id - elif self.data.models.lattice and self.data.models.lattice.beamlines: - beamline_id = self.data.models.lattice.beamlines[-1].item.id + elif self.data.models.beamlines: + beamline_id = self.data.models.beamlines[-1].id self.data.models.simulation.activeBeamlineId = ( self.data.models.simulation.visualizationBeamlineId ) = beamline_id @@ -334,10 +331,7 @@ def __parse_beamline(self, label, values): label.upper() not in self.elements_by_name ), "duplicate beamline: {}".format(label) self.elements_by_name[label.upper()] = res - self.data.models.lattice.beamlines.append(PKDict( - item=res, - model="Beamline" - )) + self.data.models.beamlines.append(res) def __parse_element(self, cmd, label, values): res = self.__parse_fields( @@ -387,10 +381,7 @@ def __parse_element(self, cmd, label, values): # assert label.upper() not in self.elements_by_name, \ # 'duplicate element labeled: {}'.format(label) self.elements_by_name[label.upper()] = res - self.data.models.elements.elements.append(PKDict( - item=res, - model=res.type - )) + self.data.models.elements.append(res) def __parse_fields(self, cmd, values, res): model_schema = self.schema.model.get(cmd) @@ -672,36 +663,28 @@ def iterate_models(self, iterator, name=None): By default the commands and elements containers are iterated. """ iterator.id_map = self.id_map - o = None - if name == "elements": - o = self.data.models.elements.elements - elif name == "beamlines": - o = self.data.models.lattice.beamlines - e = (list(map(lambda i: i.item, o)) if o is not None else self.data.models[name]) if name else self.data.models.commands + list(map(lambda i: i.item, self.data.models.elements.elements)) - for m in e: - model_schema = self.schema.model[self.model_name_for_data(m)] - iterator.start(m) - for k in sorted(m): - if k in model_schema: - iterator.field(m, model_schema[k], k) - iterator.end(m) + names = (name,) if name else ("commands", "elements") + for name in names: + for m in self.data.models[name]: + model_schema = self.schema.model[self.model_name_for_data(m)] + iterator.start(m) + for k in sorted(m): + if k in model_schema: + iterator.field(m, model_schema[k], k) + iterator.end(m) return iterator @classmethod def max_id(cls, data): max_id = 1 - e = [] - if "elements" in data.models: - e += map(lambda i: i.item, data.models.elements.elements) - if "lattice" in data.models: - e += map(lambda i: i.item, data.models.lattice.beamlines) - if "commands" in data.models: - e += data.models.commands - for m in e: - assert "_id" in m or "id" in m, "Missing id: {}".format(m) - i = m._id if "_id" in m else m.id - if i > max_id: - max_id = i + for model_type in "elements", "beamlines", "commands": + if model_type not in data.models: + continue + for m in data.models[model_type]: + assert "_id" in m or "id" in m, "Missing id: {}".format(m) + i = m._id if "_id" in m else m.id + if i > max_id: + max_id = i return max_id @classmethod @@ -773,15 +756,15 @@ def select_beamline(self): beamline_id = sim.activeBeamlineId else: if "visualizationBeamlineId" not in sim or not sim.visualizationBeamlineId: - sim.visualizationBeamlineId = self.data.models.lattice.beamlines[0].item.id + sim.visualizationBeamlineId = self.data.models.beamlines[0].id beamline_id = sim.visualizationBeamlineId return self.id_map[int(beamline_id)] def sort_elements_and_beamlines(self): """Sort elements and beamline models in place, by (type, name) and (name)""" m = self.data.models - m.elements.elements = sorted(m.elements.elements, key=lambda e: (e.item.type, e.item.name.lower())) - m.lattice.beamlines = sorted(m.lattice.beamlines, key=lambda e: e.item.name.lower()) + m.elements = sorted(m.elements, key=lambda e: (e.type, e.name.lower())) + m.beamlines = sorted(m.beamlines, key=lambda e: e.name.lower()) @classmethod def type_for_data(cls, model): @@ -799,9 +782,9 @@ def __add_beamlines(self, beamline, beamlines, ordered_beamlines): def __build_id_map(self, data): """Returns a map of beamlines and elements, (id => model).""" res = {} - for bl in map(lambda i: i.item, data.models.lattice.beamlines): + for bl in data.models.beamlines: res[bl.id] = bl - for el in map(lambda i: i.item, data.models.elements.elements): + for el in data.models.elements: res[el._id] = el if "commands" in data.models: for cmd in data.models.commands: diff --git a/sirepo/template/madx.py b/sirepo/template/madx.py index 4ec34da8b5..8c10495eaf 100644 --- a/sirepo/template/madx.py +++ b/sirepo/template/madx.py @@ -249,10 +249,9 @@ def _model(model, name): for k, v in data.models.items(): if k in SCHEMA.model: _model(v, k) - for m in data.models["commands"]: - _model(m, LatticeUtil.model_name_for_data(m)) - for m in map(lambda i: i.item, data.models.elements.elements): - _model(m, LatticeUtil.model_name_for_data(m)) + for x in ("elements", "commands"): + for m in data.models[x]: + _model(m, LatticeUtil.model_name_for_data(m)) def extract_parameter_report( @@ -375,7 +374,6 @@ def post_execution_processing(success_exit, run_dir, **kwargs): def prepare_for_client(data, qcall, **kwargs): - pkdp(data.models.rpnVariables) code_var(data.models.rpnVariables).compute_cache(data, SCHEMA) return data @@ -436,9 +434,8 @@ def to_string(value): def uniquify_elements(data): def _do_unique(elem_ids): - ae = map(lambda i: i.item, data.models.elements.elements) - element_map = PKDict({e._id: e for e in ae}) - names = set([e.name for e in ae]) + element_map = PKDict({e._id: e for e in data.models.elements}) + names = set([e.name for e in data.models.elements]) max_id = LatticeUtil.max_id(data) res = [] for el_id in elem_ids: @@ -449,8 +446,7 @@ def _do_unique(elem_ids): el.name = _unique_name(el.name, names) max_id += 1 el._id = max_id - #data.models.elements.append(el) garsuga: why mutate this when res is returned??? - data.models.elements.elements.append(PKDict(model=el.type, item=el)) + data.models.elements.append(el) res.append(el._id) return res @@ -506,10 +502,10 @@ def _reduce_to_elements_with_reflection(beamline): def _remove_unused_elements(items): res = [] - for el in data.models.elements.elements: - if el.item._id in items: + for el in data.models.elements: + if el._id in items: res.append(el) - data.models.elements.elements = res + data.models.elements = res def _unique_name(name, names): assert name in names @@ -523,12 +519,12 @@ def _unique_name(name, names): names.add(f"{name}{count}") return f"{name}{count}" - beamline_map = PKDict({b.id: b for b in map(lambda i: i.item, data.models.lattice.beamlines)}) + beamline_map = PKDict({b.id: b for b in data.models.beamlines}) b = beamline_map[data.models.simulation.visualizationBeamlineId] _reduce_to_elements_with_reflection(b) _remove_unused_elements(b["items"]) b["items"] = _do_unique(b["items"]) - data.models.lattice.beamlines = [PKDict(item=b, model="Beamline")] + data.models.beamlines = [b] def write_parameters(data, run_dir, is_parallel, filename=MADX_INPUT_FILE): @@ -581,13 +577,13 @@ def _add_commands(data, util): def _add_marker_and_observe(data): def _add_marker(data): assert ( - len(data.models.lattice.beamlines) == 1 - ), f"should have only one beamline reduced to elements. beamlines={data.models.lattice.beamlines}" - beam = data.models.lattice.beamlines[0].item + len(data.models.beamlines) == 1 + ), f"should have only one beamline reduced to elements. beamlines={data.models.beamlines}" + beam = data.models.beamlines[0] markers = PKDict() m = LatticeUtil.max_id(data) el_map = PKDict() - for el in map(lambda i: i.item, data.models.elements.elements): + for el in data.models.elements: el_map[el._id] = el items_copy = beam["items"].copy() bi = 0 @@ -604,16 +600,12 @@ def _add_marker(data): bi += 1 n = f"Marker{m}_{el.type}" markers[m] = n - data.models.elements.elements.append( + data.models.elements.append( PKDict( - model="MARKER", - item=PKDict( - _id=m, - name=n, - type="MARKER", - ) + _id=m, + name=n, + type="MARKER", ) - ) return markers, m diff --git a/sirepo/template/madx_converter.py b/sirepo/template/madx_converter.py index 4452a2ea3d..d7931d0f2d 100644 --- a/sirepo/template/madx_converter.py +++ b/sirepo/template/madx_converter.py @@ -108,15 +108,12 @@ def _convert(self, data): return self.result def _copy_beamlines(self, data): - for bl in map(lambda i: i.item, data.models.lattice.beamlines): + for bl in data.models.beamlines: self.result.models.beamlines.append( PKDict( - item=PKDict( - name=bl.name, - items=bl["items"], - id=bl.id, - ), - model="Beamline" + name=bl.name, + items=bl["items"], + id=bl.id, ) ) for f in ("name", "visualizationBeamlineId", "activeBeamlineId"): @@ -140,7 +137,7 @@ def _copy_code_variables(self, data): self.result.models.rpnVariables = res def _copy_elements(self, data): - for el in map(lambda i: i.item, data.models.elements.elements): + for el in data.models.elements: if el.type not in self.field_map: pkdlog("Unhandled element type: {}", el.type) el.type = self.drift_type @@ -161,10 +158,7 @@ def _copy_elements(self, data): values[f1] = el[f2] self._fixup_element(el, values) self.to_class.update_model_defaults(values, values.type) - self.result.models.elements.elements.append(PKDict( - item=values, - model=values.type - )) + self.result.models.elements.append(values) def _find_var(self, data, name): name = self._var_name(name) diff --git a/sirepo/template/madx_parser.py b/sirepo/template/madx_parser.py index a3ae4d1bc4..3d4415fe0b 100644 --- a/sirepo/template/madx_parser.py +++ b/sirepo/template/madx_parser.py @@ -91,8 +91,7 @@ def __convert_references_to_ids(self): # assert name not in name_to_id, 'duplicate name: {}'.format(name) name_to_id[name] = id for container in ("elements", "commands"): - dm = map(lambda i: i.item, self.data.models[container].elements) if container == "elements" else self.data.models[container] - for el in dm: + for el in self.data.models[container]: model_schema = self.schema.model[ lattice.LatticeUtil.model_name_for_data(el) ] @@ -155,10 +154,7 @@ def __convert_sequences_to_beamlines(self, code_var): if d: beamline["items"].append(d) beamline.id = self.parser.next_id() - data.models.lattice.beamlines.append(PKDict( - item=beamline, - model="Beamline" - )) + data.models.beamlines.append(beamline) del data.models["sequences"] util.sort_elements_and_beamlines() diff --git a/sirepo/template/shadow.py b/sirepo/template/shadow.py index b9c44bdf78..dcbfbcb213 100644 --- a/sirepo/template/shadow.py +++ b/sirepo/template/shadow.py @@ -184,7 +184,6 @@ def python_source_for_model(data, model, qcall, **kwargs): if not model: beamline = data.models.beamline watch_id = None - watch_index = None for b in beamline: if b.type == "watch": watch_id = b.id From 0921f71c8e47f160bc5bf659d3c3383265674286 Mon Sep 17 00:00:00 2001 From: moellep Date: Wed, 31 May 2023 16:47:14 +0000 Subject: [PATCH 61/68] for #5914 update shadow tests --- tests/template/srw_shadow_data/to_shadow_crl.out/shadow.json | 1 + tests/template/srw_shadow_data/to_shadow_gauss.out/shadow.json | 1 + tests/template/srw_shadow_data/to_shadow_grating.out/shadow.json | 1 + 3 files changed, 3 insertions(+) diff --git a/tests/template/srw_shadow_data/to_shadow_crl.out/shadow.json b/tests/template/srw_shadow_data/to_shadow_crl.out/shadow.json index 9724d7751b..58be7c3a6f 100644 --- a/tests/template/srw_shadow_data/to_shadow_crl.out/shadow.json +++ b/tests/template/srw_shadow_data/to_shadow_crl.out/shadow.json @@ -260,6 +260,7 @@ "column": "6", "distanceFromSource": 0, "histogramBins": 100, + "notes": "", "weight": "22" }, "initialIntensityReport": { diff --git a/tests/template/srw_shadow_data/to_shadow_gauss.out/shadow.json b/tests/template/srw_shadow_data/to_shadow_gauss.out/shadow.json index 0c77b0b138..3f4ecd8624 100644 --- a/tests/template/srw_shadow_data/to_shadow_gauss.out/shadow.json +++ b/tests/template/srw_shadow_data/to_shadow_gauss.out/shadow.json @@ -109,6 +109,7 @@ "column": "6", "distanceFromSource": 0, "histogramBins": 100, + "notes": "", "weight": "22" }, "initialIntensityReport": { diff --git a/tests/template/srw_shadow_data/to_shadow_grating.out/shadow.json b/tests/template/srw_shadow_data/to_shadow_grating.out/shadow.json index 2d74c86c25..df3628e4fc 100644 --- a/tests/template/srw_shadow_data/to_shadow_grating.out/shadow.json +++ b/tests/template/srw_shadow_data/to_shadow_grating.out/shadow.json @@ -271,6 +271,7 @@ "column": "6", "distanceFromSource": 0, "histogramBins": 100, + "notes": "", "weight": "22" }, "initialIntensityReport": { From 4570d305907843329a51f5f6480101fdbae95888 Mon Sep 17 00:00:00 2001 From: moellep Date: Wed, 31 May 2023 17:29:03 +0000 Subject: [PATCH 62/68] for #5914 unformat in api save, with TODO --- sirepo/server.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sirepo/server.py b/sirepo/server.py index 33b0108e1a..7f120cd0a6 100644 --- a/sirepo/server.py +++ b/sirepo/server.py @@ -524,6 +524,9 @@ async def api_saveSimulationData(self): req = self.parse_post(id=True, template=True) d = req.req_data simulation_db.validate_serial(d, qcall=self) + # TODO(pjm): this should happen with the fixup below, but is not + if sirepo.feature_config.is_react_sim_type(req.type): + req.sim_data.react_unformat_data(d) return self._simulation_data_reply( req, simulation_db.save_simulation_json( From 315bb24f3af96a69449d96d0e225fca1ca2a3d8e Mon Sep 17 00:00:00 2001 From: moellep Date: Thu, 1 Jun 2023 17:29:08 +0000 Subject: [PATCH 63/68] pass nextRequest info to runStatus, models is optional --- react/src/utility/compute.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/react/src/utility/compute.ts b/react/src/utility/compute.ts index d70218d730..5aa8576a90 100644 --- a/react/src/utility/compute.ts +++ b/react/src/utility/compute.ts @@ -85,14 +85,12 @@ export function pollRunReport(routeHelper: RouteHelper, { appName, models, simul doFetch().then(resp => { callback(resp); - pollRunStatus(routeHelper, { - callback, - simulationId, - models, - appName, - report, - forceRun - }); + if (resp.nextRequest) { + pollRunStatus(routeHelper, { + callback: callback, + ...resp.nextRequest, + }); + } }); } @@ -121,7 +119,7 @@ export function cancelReport(routeHelper: RouteHelper, { appName, models, simula export type RunStatusParams = { appName: string, - models: StoreState, + models?: StoreState, simulationId: string, report: string, forceRun: boolean @@ -142,7 +140,7 @@ export function getRunStatusOnce(routeHelper: RouteHelper, { appName, ...otherPa return new Promise((resolve, reject) => { doStatus().then(async lastResp => resolve(await lastResp.json())); }) - + } export type RunStatusPollParams = { From 385b14b0ce0f4979da42a06338090baeb89fdf37 Mon Sep 17 00:00:00 2001 From: moellep Date: Thu, 1 Jun 2023 17:31:58 +0000 Subject: [PATCH 64/68] for #5914 move react un/format to http_request --- sirepo/http_request.py | 7 +++++-- sirepo/job_api.py | 12 +++++------- sirepo/server.py | 9 +-------- sirepo/simulation_db.py | 5 +---- 4 files changed, 12 insertions(+), 21 deletions(-) diff --git a/sirepo/http_request.py b/sirepo/http_request.py index 00ebcbb3a2..b6d24e08da 100644 --- a/sirepo/http_request.py +++ b/sirepo/http_request.py @@ -62,8 +62,11 @@ def parse_post(qcall, kwargs): r = kwargs.pkdel("req_data") if r is None: r = parse_json(qcall) - if kwargs.pkdel("fixup_old_data"): - r = simulation_db.fixup_old_data(r, qcall=qcall)[0] + assert not kwargs.get("fixup_old_data") + if kwargs.pkdel("is_sim_data"): + s = sirepo.sim_data.get_class(r) + if sirepo.feature_config.is_react_sim_type(s.sim_type()) and r.get("models"): + s.react_unformat_data(r) res.pkupdate(req_data=r) kwargs.pksetdefault(type=True) diff --git a/sirepo/job_api.py b/sirepo/job_api.py index d264d9fbc4..e96596cf71 100644 --- a/sirepo/job_api.py +++ b/sirepo/job_api.py @@ -183,14 +183,16 @@ def _api(api): @sirepo.quest.Spec("require_user") async def api_runSimulation(self): - r = self._request_content(PKDict(fixup_old_data=True)) + r = self._request_content(PKDict(is_sim_data=True)) if r.isParallel: r.isPremiumUser = self.auth.is_premium_user() return await self._request_api(_request_content=r) @sirepo.quest.Spec("require_user") async def api_runStatus(self): - return await self._request_api() + # runStatus receives models when an animation status if first queried + r = self._request_content(PKDict(is_sim_data=True)) + return await self._request_api(_request_content=r) @sirepo.quest.Spec("require_user") async def api_sbatchLogin(self): @@ -319,16 +321,12 @@ def _request_content(self, kwargs): # of the used values are modified by parse_post. If we have files (e.g. file_type, filename), # we need to use those values from parse_post d = self.parse_post( - fixup_old_data=kwargs.pkdel("fixup_old_data", False), + is_sim_data=kwargs.pkdel("is_sim_data", False), id=True, model=True, check_sim_exists=True, ).req_data s = sirepo.sim_data.get_class(d) - if sirepo.feature_config.is_react_sim_type(s.sim_type()): - # TODO(pjm): need to know if this is the full sirepo data - if d.get("models"): - s.react_unformat_data(d) ##TODO(robnagler) this should be req_data b = PKDict(data=d, **kwargs) # TODO(e-carlin): some of these fields are only used for some type of reqs diff --git a/sirepo/server.py b/sirepo/server.py index 7f120cd0a6..c2b876e763 100644 --- a/sirepo/server.py +++ b/sirepo/server.py @@ -521,12 +521,9 @@ async def api_root(self, path_info=None): @sirepo.quest.Spec("require_user", sid="SimId", data="SimData all_input") async def api_saveSimulationData(self): # do not fixup_old_data yet - req = self.parse_post(id=True, template=True) + req = self.parse_post(id=True, template=True, is_sim_data=True) d = req.req_data simulation_db.validate_serial(d, qcall=self) - # TODO(pjm): this should happen with the fixup below, but is not - if sirepo.feature_config.is_react_sim_type(req.type): - req.sim_data.react_unformat_data(d) return self._simulation_data_reply( req, simulation_db.save_simulation_json( @@ -781,10 +778,6 @@ def _save_new_and_reply(self, req, data): def _simulation_data_reply(self, req, data): if hasattr(req.template, "prepare_for_client"): - # TODO(pjm): for some reason _simulation_data_reply() can be called twice in one request - # see madx FODO PTC example - if sirepo.feature_config.is_react_sim_type(req.type): - req.sim_data.react_unformat_data(data) d = req.template.prepare_for_client(data, qcall=self) if sirepo.feature_config.is_react_sim_type(req.type): req.sim_data.react_format_data(data) diff --git a/sirepo/simulation_db.py b/sirepo/simulation_db.py index f8953d0e6a..79fe469953 100644 --- a/sirepo/simulation_db.py +++ b/sirepo/simulation_db.py @@ -249,10 +249,7 @@ def _last_modified(data, path): data.models.simulation.lastModified = _last_modified(data, path) from sirepo import sim_data - s = sim_data.get_class(data.simulationType) - if sirepo.feature_config.is_react_sim_type(s.sim_type()): - s.react_unformat_data(data) - s.fixup_old_data(data, qcall=qcall) + sim_data.get_class(data.simulationType).fixup_old_data(data, qcall=qcall) data.pkdel("fixup_old_version") return data, True except Exception as e: From 2b9247ad964a8d144c1cf55c9bcb8044548c2b5d Mon Sep 17 00:00:00 2001 From: moellep Date: Thu, 1 Jun 2023 17:32:57 +0000 Subject: [PATCH 65/68] for #5914 fix shadow report dependencies --- .../static/react-json/shadow-schema.json | 18 +++++++++++++----- sirepo/sim_data/madx.py | 2 -- sirepo/sim_data/shadow.py | 2 +- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/sirepo/package_data/static/react-json/shadow-schema.json b/sirepo/package_data/static/react-json/shadow-schema.json index fb71988b0a..756595266b 100644 --- a/sirepo/package_data/static/react-json/shadow-schema.json +++ b/sirepo/package_data/static/react-json/shadow-schema.json @@ -4108,7 +4108,9 @@ "electronBeam.*", "geometricSource.*", "rayFilter.*", - "simulation.*", + "simulation.sourceType", + "simulation.npoint", + "simulation.istar1", "sourceDivergence.*", "undulator.*", "undulatorBeam.*", @@ -4153,7 +4155,9 @@ "electronBeam.*", "geometricSource.*", "rayFilter.*", - "simulation.*", + "simulation.sourceType", + "simulation.npoint", + "simulation.istar1", "sourceDivergence.*", "undulator.*", "undulatorBeam.*", @@ -5073,7 +5077,9 @@ "electronBeam.*", "geometricSource.*", "rayFilter.*", - "simulation.*", + "simulation.sourceType", + "simulation.npoint", + "simulation.istar1", "sourceDivergence.*", "undulator.*", "undulatorBeam.*", @@ -5177,7 +5183,9 @@ "electronBeam.*", "geometricSource.*", "rayFilter.*", - "simulation.*", + "simulation.sourceType", + "simulation.npoint", + "simulation.istar1", "sourceDivergence.*", "undulator.*", "undulatorBeam.*", @@ -5221,7 +5229,7 @@ } ] } - + } ] } diff --git a/sirepo/sim_data/madx.py b/sirepo/sim_data/madx.py index 6524d3a2c5..fdb83f74e4 100644 --- a/sirepo/sim_data/madx.py +++ b/sirepo/sim_data/madx.py @@ -29,7 +29,6 @@ def fixup_old_data(cls, data, qcall, **kwargs): @classmethod def react_format_data(cls, data): - pkdp("madx format data") dm = data.models if "beamlines" in dm: assert isinstance(dm.beamlines, list) @@ -46,7 +45,6 @@ def react_format_data(cls, data): @classmethod def react_unformat_data(cls, data): - pkdp("madx unformat data") dm = data.models if isinstance(dm.elements, list): return diff --git a/sirepo/sim_data/shadow.py b/sirepo/sim_data/shadow.py index 7a7f714b08..eaa50d0c8c 100644 --- a/sirepo/sim_data/shadow.py +++ b/sirepo/sim_data/shadow.py @@ -98,7 +98,7 @@ def shadow_wiggler_file(cls, value): @classmethod def _compute_job_fields(cls, data, r, compute_model): - assert r in data.models + assert r in data.models, f"unknown report: {r}" res = cls._non_analysis_fields(data, r) + [ "bendingMagnet", "electronBeam", From 0ad14ec5f5542a9bfecb8a00c979ebc7bae71903 Mon Sep 17 00:00:00 2001 From: moellep Date: Tue, 13 Jun 2023 16:11:27 +0000 Subject: [PATCH 66/68] fix #5942 match silas sim to notebook results - fix problem with axis ticks for range [-0.02, 0] - fix broken silas percentComplete --- .../package_data/static/js/sirepo-plotting.js | 11 +- .../static/json/silas-schema.json | 18 ++- .../template/silas/parameters.py.jinja | 3 +- sirepo/template/silas.py | 103 +++++++++--------- tests/karma/plotAxis_test.js | 9 +- 5 files changed, 80 insertions(+), 64 deletions(-) diff --git a/sirepo/package_data/static/js/sirepo-plotting.js b/sirepo/package_data/static/js/sirepo-plotting.js index 66300afa54..ab47b4bd83 100644 --- a/sirepo/package_data/static/js/sirepo-plotting.js +++ b/sirepo/package_data/static/js/sirepo-plotting.js @@ -1814,19 +1814,14 @@ SIREPO.app.service('layoutService', function(panelState, plotting, utilities) { const v0 = applyUnit(tickValues[0], base, unit); const v1 = applyUnit(tickValues[1], base, unit); const vn = applyUnit(tickValues[tickValues.length - 1], base, unit); - let decimals; - if (Math.abs(v0) > Math.abs(vn)) { - decimals = d3_precisionRound(v1 - v0, Math.abs(v0)); - } - else { - decimals = d3_precisionRound(v1 - v0, vn); - } + const max = Math.abs(v0) > Math.abs(vn) ? Math.abs(v0) : vn; + let decimals = d3_precisionRound(v1 - v0, max); if (decimals > 1) { decimals -= 1; } if (useFloatFormat(v0) && useFloatFormat(vn)) { code = 'f'; - decimals -= valuePrecision(vn); + decimals -= valuePrecision(max); if (decimals < 0) { decimals = 0; } diff --git a/sirepo/package_data/static/json/silas-schema.json b/sirepo/package_data/static/json/silas-schema.json index b8ef60fff3..fee8ff226d 100644 --- a/sirepo/package_data/static/json/silas-schema.json +++ b/sirepo/package_data/static/json/silas-schema.json @@ -123,7 +123,10 @@ "pump_gaussian_order": ["Pump Gaussian Order", "Float", 2.0], "pump_type": ["Pump Type", "PumpType", "dual"], "origin": ["Crystal", "CrystalOrigin", "new"], - "reuseCrystal": ["Select Crystal", "SelectCrystal", 0] + "reuseCrystal": ["Select Crystal", "SelectCrystal", 0], + "pump_offset_x": ["Pump Offset X [m]", "Float", 0], + "pump_offset_y": ["Pump Offset X [m]", "Float", 0], + "pump_rep_rate": ["Pump Rep Rate", "Float", 1.0] }, "crystalAnimation": {}, "crystalSettings": { @@ -160,7 +163,8 @@ "pulseE": ["Total Laser Pulse Energy [J]", "Float", 0.001], "distribution": ["Distribution Type", "DistributionType", "gaussian"], "sigx_waist": ["Horizontal RMS Waist Size [m]", "Float", 0.001], - "sigy_waist": ["Vertical RMS Waist Size [m]", "Float", 0.001] + "sigy_waist": ["Vertical RMS Waist Size [m]", "Float", 0.001], + "phase_flatten_cutoff": ["Phase Flatten Cutoff", "Float", 0.85] }, "laserPulseAnimation": { "_super": ["_", "model", "initialIntensityReport"] @@ -171,7 +175,7 @@ }, "initialIntensityReport": { "colorMap": ["Color Map", "ColorMap", "viridis"], - "watchpointPlot": ["Value to Plot", "WatchpointPlot", "intensity"] + "watchpointPlot": ["Value to Plot", "WatchpointPlot", "total_intensity"] }, "lens": { "_super": ["_", "model", "beamElement"], @@ -229,7 +233,10 @@ "pump_waist", "pump_wavelength", "pump_energy", - "pump_gaussian_order" + "pump_gaussian_order", + "pump_rep_rate", + "pump_offset_x", + "pump_offset_y" ]] ] }, @@ -282,7 +289,8 @@ ["Energy", [ "photon_e_ev", "chirp", - "pulseE" + "pulseE", + "phase_flatten_cutoff" ]], ["Transverse", [ "num_sig_trans", diff --git a/sirepo/package_data/template/silas/parameters.py.jinja b/sirepo/package_data/template/silas/parameters.py.jinja index ec895604a6..d5c25d5929 100644 --- a/sirepo/package_data/template/silas/parameters.py.jinja +++ b/sirepo/package_data/template/silas/parameters.py.jinja @@ -116,7 +116,8 @@ pulse = LaserPulse( 'pulseE', 'sigx_waist', 'sigy_waist', - 'tau_fwhm' + 'tau_fwhm', + 'phase_flatten_cutoff', ) %} {{ f }}={{ laserPulse[f] }}, {% endfor %} diff --git a/sirepo/template/silas.py b/sirepo/template/silas.py index 4327f78880..e6b3e3b0cc 100644 --- a/sirepo/template/silas.py +++ b/sirepo/template/silas.py @@ -14,9 +14,7 @@ import numpy import re import sirepo.sim_data - -# TODO(pjm): currently aligned with rslaser version -# git checkout `git rev-list -n 1 --first-parent --before="2023-04-24 13:37" main` +import time _SIM_DATA, SIM_TYPE, SCHEMA = sirepo.sim_data.template_globals() @@ -134,8 +132,7 @@ def write_parameters(data, run_dir, is_parallel): def _beamline_animation_percent_complete(run_dir, res, data): - def _output_append(frame_count, filename, count, element, res, total_count): - total_count += 1 + def _output_append(frame_count, filename, count, element, res): if run_dir.join(filename).exists(): res.outputInfo.append( PKDict( @@ -165,20 +162,19 @@ def _frames(element, data): _initial_intensity_percent_complete(run_dir, res, data, ("beamlineAnimation0",)) count = PKDict( watch=1, - crystal=1, + crystal=0, ) total_count = 1 for e in data.models.beamline: if e.type in ("watch", "crystal"): + total_count += 1 _output_append( _frames(e, data), _file(e, count), count, e, res, - total_count, ) - res.percentComplete = res.frameCount * 100 / total_count return res @@ -300,16 +296,17 @@ def _generate_crystal(crystal): B={crystal.B}, C={crystal.C}, D={crystal.D}, - population_inversion=PKDict( - n_cells={crystal.inversion_n_cells}, - mesh_extent={crystal.inversion_mesh_extent}, - crystal_alpha={crystal.crystal_alpha}, - pump_waist={crystal.pump_waist}, - pump_wavelength={crystal.pump_wavelength}, - pump_gaussian_order={crystal.pump_gaussian_order}, - pump_energy={crystal.pump_energy}, - pump_type="{crystal.pump_type}", - ), + pop_inversion_n_cells={crystal.inversion_n_cells}, + pop_inversion_mesh_extent={crystal.inversion_mesh_extent}, + pop_inversion_crystal_alpha={crystal.crystal_alpha}, + pop_inversion_pump_waist={crystal.pump_waist}, + pop_inversion_pump_wavelength={crystal.pump_wavelength}, + pop_inversion_pump_gaussian_order={crystal.pump_gaussian_order}, + pop_inversion_pump_energy={crystal.pump_energy}, + pop_inversion_pump_type="{crystal.pump_type}", + pop_inversion_pump_rep_rate={crystal.pump_rep_rate}, + pop_inversion_pump_offset_x={crystal.pump_offset_x}, + pop_inversion_pump_offset_y={crystal.pump_offset_y}, ), ), ["{crystal.propagationType}", {crystal.calc_gain == "1"}, {crystal.radial_n2 == "1"}], @@ -415,37 +412,45 @@ def _y_value(element, index, file, cell_volume): return y return numpy.sum(y) - with h5py.File(run_dir.join(_fname(element).format(element_index)), "r") as f: - if _is_longitudinal_plot(plot_type): - x = [] - y = [] - nslice = _nslice(element, f) - if element: - element.nslice = nslice - for idx in range(nslice): - x.append(idx) - y.append(_y_value(element, idx, f, _cell_volume(element))) - return template_common.parameter_plot( - x, - [ - PKDict( - points=y, - label=_label(plot_type), - ), - ], - PKDict(), - ) - d = template_common.h5_to_dict(f, str(slice_index)) - r = d.ranges - z = d[plot_type] - return PKDict( - title=_title(plot_type, slice_index), - x_range=[r.x[0], r.x[1], len(z)], - y_range=[r.y[0], r.y[1], len(z[0])], - x_label="Horizontal Position [m]", - y_label="Vertical Position [m]", - z_matrix=z, - ) + tries = 3 + for _ in range(tries): + try: + with h5py.File( + run_dir.join(_fname(element).format(element_index)), "r" + ) as f: + if _is_longitudinal_plot(plot_type): + x = [] + y = [] + nslice = _nslice(element, f) + if element: + element.nslice = nslice + for idx in range(nslice): + x.append(idx) + y.append(_y_value(element, idx, f, _cell_volume(element))) + return template_common.parameter_plot( + x, + [ + PKDict( + points=y, + label=_label(plot_type), + ), + ], + PKDict(), + ) + d = template_common.h5_to_dict(f, str(slice_index)) + r = d.ranges + z = d[plot_type] + return PKDict( + title=_title(plot_type, slice_index), + x_range=[r.x[0], r.x[1], len(z)], + y_range=[r.y[0], r.y[1], len(z[0])], + x_label="Horizontal Position [m]", + y_label="Vertical Position [m]", + z_matrix=z, + ) + except BlockingIOError as e: + time.sleep(3) + raise AssertionError("Report is unavailable") def _laser_pulse_report(value_index, filename, title, label): diff --git a/tests/karma/plotAxis_test.js b/tests/karma/plotAxis_test.js index a985942f20..2cdcdcabff 100644 --- a/tests/karma/plotAxis_test.js +++ b/tests/karma/plotAxis_test.js @@ -111,7 +111,14 @@ describe('plotting: plotAxis', function() { tickValues('', [-0.0002, -0.0018], {width: 315, height: 200}, 'y', 'left'), ['-1.5e-3', '-1.0e-3', '-5.0e-4'], ); - + assertTicks( + tickValues('', [-0.02, 0], {width: 350, height: 180}, 'y', 'left'), + ['-0.02', '-0.01', '0'], + ); + assertTicks( + tickValues('', [0, 0.02], {width: 350, height: 180}, 'y', 'left'), + ['0', '0.01', '0.02'], + ); })); it('should format units', inject(function(layoutService) { expect(layoutService.formatUnits('m')).toEqual('[m]'); From 36a73fd5c4ff0b7cdcb1cf2e34be873ae05dcb64 Mon Sep 17 00:00:00 2001 From: moellep Date: Tue, 13 Jun 2023 19:14:51 +0000 Subject: [PATCH 67/68] undo formatting change --- .../package_data/static/js/sirepo-lattice.js | 478 +++++++++--------- 1 file changed, 239 insertions(+), 239 deletions(-) diff --git a/sirepo/package_data/static/js/sirepo-lattice.js b/sirepo/package_data/static/js/sirepo-lattice.js index b3d876767e..28b22fb82b 100644 --- a/sirepo/package_data/static/js/sirepo-lattice.js +++ b/sirepo/package_data/static/js/sirepo-lattice.js @@ -3,27 +3,27 @@ var srlog = SIREPO.srlog; var srdbg = SIREPO.srdbg; -SIREPO.app.config(function () { +SIREPO.app.config(function() { SIREPO.appFieldEditors += [ '
', - '
', + '
', '
', '
', - '
', + '
', '
', '
', - '
', + '
', '
', '
', - '
', + '
', '
', '
', - '
', + '
', '
', ].join(''); }); -SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, utilities, validationService, $rootScope) { +SIREPO.app.factory('latticeService', function(appState, panelState, rpnService, utilities, validationService, $rootScope) { var self = {}; var COMMAND_PREFIX = 'command_'; self.activeBeamlineId = null; @@ -56,11 +56,11 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, function elementNameValidator(currentName) { var names = self.elementNameMap(); - return function (newNameV) { + return function(newNameV) { if (newNameV == currentName) { return true; } - return !names[newNameV]; + return ! names[newNameV]; }; } @@ -91,13 +91,13 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, } function sortBeamlines() { - appState.models.beamlines.sort(function (a, b) { + appState.models.beamlines.sort(function(a, b) { return a.name.localeCompare(b.name); }); } function sortElements() { - appState.models.elements.sort(function (a, b) { + appState.models.elements.sort(function(a, b) { var res = a.type.localeCompare(b.type); if (res === 0) { res = a.name.localeCompare(b.name); @@ -118,7 +118,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, break; } } - if (!foundIt) { + if (! foundIt) { if (self.elementNameMap()[m.name]) { m.name = self.uniqueNameForType(m.name + '-'); } @@ -126,7 +126,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, } sortMethod(); // process this outside of the current digest cycle, allows lattice to update from model - panelState.waitForUI(function () { + panelState.waitForUI(function() { appState.removeModel(name); appState.saveChanges(containerName); }); @@ -134,39 +134,39 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, self.COMMAND_PREFIX = COMMAND_PREFIX; - self.addToBeamline = function (item) { + self.addToBeamline = function(item) { $rootScope.$broadcast('sr-addToBeamline', item); }; - self.angleFormat = function (angle) { + self.angleFormat = function(angle) { var degrees = self.radiansToDegrees(rpnService.getRpnValue(angle)); degrees = Math.round(degrees * 10) / 10; degrees %= 360; return degrees.toFixed(1); }; - self.arcLength = function (angle, length) { + self.arcLength = function(angle, length) { return angle * length / (2 * Math.sin(angle / 2)); }; - self.bunchReportHeading = function (modelKey) { - if (!appState.isLoaded()) { + self.bunchReportHeading = function(modelKey) { + if (! appState.isLoaded()) { return; } var bunch = appState.models[modelKey]; - if (!bunch) { + if (! bunch) { return ''; } var key = bunch.x + '-' + bunch.y; let res = plotTitle[key]; - if (!res) { + if (! res) { res = (plotTitle[bunch.x] || bunch.x) + ' / ' + (plotTitle[bunch.y] || bunch.y); } return res + ' Phase Space'; }; - self.commandModelName = function (type) { + self.commandModelName = function(type) { return COMMAND_PREFIX + type; }; @@ -175,13 +175,13 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, self.editElement(copy.type, copy); }; - self.createElement = function (type) { + self.createElement = function(type) { var model = self.getNextElement(type); appState.setModelDefaults(model, type); self.editElement(type, model); }; - self.deleteElement = function () { + self.deleteElement = function() { var type = self.deleteWarning.type; var element = self.deleteWarning.element; self.deleteWarning = null; @@ -190,7 +190,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, var el = appState.models[type][i]; if (el[idField] == element[idField]) { var saveModelNames = [type]; - if (type === 'beamlines' && el[idField] == appState.models.simulation.visualizationBeamlineId) { + if(type === 'beamlines' && el[idField] == appState.models.simulation.visualizationBeamlineId) { appState.models.simulation.visualizationBeamlineId = self.activeBeamlineId; saveModelNames.push('simulation'); } @@ -203,8 +203,8 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return; }; - self.editElement = function (type, item, models) { - if (!appState.viewInfo(type)) { + self.editElement = function(type, item, models) { + if (! appState.viewInfo(type)) { return; } if (models) { @@ -215,13 +215,13 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, panelState.showModalEditor(type); }; - self.elementNameMap = function () { + self.elementNameMap = function() { var res = {}; var containers = ['elements', 'beamlines']; if (self.includeCommandNames) { containers.push('commands'); } - containers.forEach(function (containerName) { + containers.forEach(function(containerName) { var container = appState.models[containerName] || []; for (var i = 0; i < container.length; i++) { res[container[i].name] = 1; @@ -230,27 +230,27 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return res; }; - self.degreesToRadians = function (v) { + self.degreesToRadians = function(v) { return v * Math.PI / 180; }; - self.deleteElementPrompt = function (type, element) { + self.deleteElementPrompt = function(type, element) { var idField = type == 'elements' ? '_id' : 'id'; var beamlines = self.getBeamlinesWhichContainId(element[idField]); showDeleteWarning(type, element, beamlines); }; - self.editBeamline = function (beamline, updateNoWait) { + self.editBeamline = function(beamline, updateNoWait) { self.activeBeamlineId = beamline.id; appState.models.simulation.activeBeamlineId = beamline.id; - if (!appState.models.simulation.visualizationBeamlineId) { + if (! appState.models.simulation.visualizationBeamlineId) { appState.models.simulation.visualizationBeamlineId = beamline.id; } appState.saveChanges('simulation'); $rootScope.$broadcast('activeBeamlineChanged', updateNoWait); }; - self.elementForId = function (id, models) { + self.elementForId = function(id, models) { models = models || appState.models; id = Math.abs(id); for (let i = 0; i < models.beamlines.length; i++) { @@ -268,11 +268,11 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return null; }; - self.getActiveBeamline = function () { + self.getActiveBeamline = function() { return self.elementForId(self.activeBeamlineId); }; - self.getSimulationBeamline = function () { + self.getSimulationBeamline = function() { if (appState.isLoaded()) { return self.elementForId( appState.applicationState().simulation.visualizationBeamlineId); @@ -280,7 +280,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return null; }; - self.getBeamlinesWhichContainId = function (id) { + self.getBeamlinesWhichContainId = function(id) { var res = []; for (var i = 0; i < appState.models.beamlines.length; i++) { var b = appState.models.beamlines[i]; @@ -293,11 +293,11 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return res; }; - self.nameForId = function (id) { + self.nameForId = function(id) { return self.elementForId(id).name; }; - self.getNextBeamline = function () { + self.getNextBeamline = function() { var beamline = { name: self.uniqueNameForType('BL'), id: self.nextId(), @@ -310,7 +310,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return beamline; }; - self.getNextElement = function (type) { + self.getNextElement = function(type) { return { _id: self.nextId(), type: type, @@ -318,7 +318,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, }; }; - self.hasBeamlines = function () { + self.hasBeamlines = function() { if (appState.isLoaded()) { for (var i = 0; i < appState.models.beamlines.length; i++) { var beamline = appState.models.beamlines[i]; @@ -330,49 +330,49 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return false; }; - self.initSourceController = function (controller) { - controller.bunchReports = [1, 2, 3, 4].map(function (id) { + self.initSourceController = function(controller) { + controller.bunchReports = [1, 2, 3, 4].map(function(id) { var modelKey = 'bunchReport' + id; return { id: id, modelKey: modelKey, - getData: function () { + getData: function() { return appState.models[modelKey]; }, }; }); - controller.bunchReportHeading = function (item) { + controller.bunchReportHeading = function(item) { return self.bunchReportHeading('bunchReport' + item.id); }; }; - self.isAbsolutePositioning = function () { + self.isAbsolutePositioning = function() { return appState.models.simulation.elementPosition == 'absolute'; }; - self.isCommandModelName = function (name) { + self.isCommandModelName = function(name) { return name.indexOf(COMMAND_PREFIX) === 0; }; - self.isElementModelName = function (name) { + self.isElementModelName = function(name) { var schema = SIREPO.APP_SCHEMA.model[name]; return schema && 'name' in schema && name == name.toUpperCase(); }; - self.isReversed = function (beamlineId) { + self.isReversed = function(beamlineId) { return beamlineId < 0; }; - self.newBeamline = function () { + self.newBeamline = function() { appState.models.beamline = self.getNextBeamline(); panelState.showModalEditor('beamline'); }; - self.newElement = function () { + self.newElement = function() { $('#' + panelState.modalId('newBeamlineElement')).modal('show'); }; - self.nextId = function () { + self.nextId = function() { return Math.max( appState.maxId(appState.models.elements, '_id'), appState.maxId(appState.models.beamlines), @@ -380,9 +380,9 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, }; //TODO(pjm): use library for this - self.numFormat = function (num, units) { + self.numFormat = function(num, units) { num = rpnService.getRpnValue(num); - if (!angular.isDefined(num)) { + if (! angular.isDefined(num)) { return ''; } var sign = num < 0 ? -1 : 1; @@ -399,22 +399,22 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, if (num >= 10) { return (sign * num).toFixed(2) + units; } - return (sign * num).toFixed(3) + units; + return (sign * num).toFixed(3) + units; }; - self.radiansToDegrees = function (v) { + self.radiansToDegrees = function(v) { return v * 180 / Math.PI; }; - self.setValidator = function (modelName, model) { + self.setValidator = function(modelName, model) { validationService.setFieldValidator( utilities.modelFieldID(modelName, 'name'), elementNameValidator(model.name), elementNameInvalidMsg); }; - self.showRpnVariables = function () { - appState.models.rpnVariables = appState.models.rpnVariables.sort(function (a, b) { + self.showRpnVariables = function() { + appState.models.rpnVariables = appState.models.rpnVariables.sort(function(a, b) { // work-around for #4935 put invalid variables last if (a.name === null) { return 1; @@ -427,7 +427,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, $('#sr-variables').modal('show'); }; - self.uniqueNameForType = function (prefix) { + self.uniqueNameForType = function(prefix) { var names = self.elementNameMap(); var name = prefix; var index = 1; @@ -440,11 +440,11 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, if ((SIREPO.lattice && SIREPO.lattice.useBeamlineListeners) //TODO(pjm): change DRIFT apps to use lattice.useBeamlineListeners || SIREPO.APP_SCHEMA.model.DRIFT || SIREPO.APP_SCHEMA.model.DRIF) { - appState.whenModelsLoaded($rootScope, function () { + appState.whenModelsLoaded($rootScope, function() { self.activeBeamlineId = appState.models.simulation.activeBeamlineId; }); - $rootScope.$on('modelChanged', function (e, name) { + $rootScope.$on('modelChanged', function(e, name) { if (name == 'beamline') { fixModelName(name); var id = appState.models.beamline.id; @@ -457,7 +457,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, } }); - $rootScope.$on('cancelChanges', function (e, name) { + $rootScope.$on('cancelChanges', function(e, name) { if (name == 'beamline') { appState.removeModel(name); appState.cancelChanges('beamlines'); @@ -468,7 +468,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, } }); - $rootScope.$on('modelsUnloaded', function () { + $rootScope.$on('modelsUnloaded', function() { self.activeBeamlineId = null; self.selectedItem = null; }); @@ -477,7 +477,7 @@ SIREPO.app.factory('latticeService', function (appState, panelState, rpnService, return self; }); -SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) { +SIREPO.app.service('rpnService', function(appState, requestSender, $rootScope) { var rpnBooleanValues = null; var self = this; self.isCaseInsensitive = false; @@ -486,7 +486,7 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) rpnBooleanValues = null; } - self.computeRpnValue = function (value, callback) { + self.computeRpnValue = function(value, callback) { if (self.isCaseInsensitive) { value = value.toLowerCase ? value.toLowerCase() : value; } @@ -496,8 +496,8 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) } requestSender.sendRpn( appState, - function (data) { - if (!data.error) { + function(data) { + if (! data.error) { if (appState.isLoaded()) { appState.models.rpnCache[value] = data.result; } @@ -511,16 +511,16 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) ); }; - self.getRpnBooleanForField = function (model, field) { + self.getRpnBooleanForField = function(model, field) { if (appState.isLoaded() && model && field) { - if (!rpnBooleanValues) { + if (! rpnBooleanValues) { rpnBooleanValues = []; if (appState.models.rpnVariables) { for (var i = 0; i < appState.models.rpnVariables.length; i++) { var v = appState.models.rpnVariables[i]; rpnBooleanValues.push([v.name, 'var: ' + v.name]); } - rpnBooleanValues = rpnBooleanValues.sort(function (a, b) { + rpnBooleanValues = rpnBooleanValues.sort(function(a, b) { return a[1].localeCompare(b[1]); }); } @@ -533,7 +533,7 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) return null; }; - self.getRpnValue = function (v) { + self.getRpnValue = function(v) { if (angular.isUndefined(v) || v === null) { return v; } @@ -550,7 +550,7 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) return value; }; - self.getRpnValueForField = function (model, field) { + self.getRpnValueForField = function(model, field) { if (appState.isLoaded() && model && field) { var v = model[field]; if (SIREPO.NUMBER_REGEXP.test(v)) { @@ -561,7 +561,7 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) return ''; }; - self.recomputeCache = function (varName, value) { + self.recomputeCache = function(varName, value) { var recomputeRequired = false; var re = new RegExp("\\b" + varName + "\\b"); for (var k in appState.models.rpnCache) { @@ -572,12 +572,12 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) recomputeRequired = true; } } - if (!recomputeRequired) { + if (! recomputeRequired) { return; } requestSender.sendRpn( appState, - function (data) { + function(data) { if (appState.isLoaded() && data.cache) { appState.models.rpnCache = data.cache; } @@ -592,7 +592,7 @@ SIREPO.app.service('rpnService', function (appState, requestSender, $rootScope) appState.whenModelsLoaded($rootScope, clearBooleanValues); }); -SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panelState, rpnService, $document, $rootScope, $window) { +SIREPO.app.directive('beamlineEditor', function(appState, latticeService, panelState, rpnService, $document, $rootScope, $window) { return { restrict: 'A', // transcluded data contains html for tab panels defined with headerTabInfo @@ -659,7 +659,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel
`, - controller: function ($scope) { + controller: function($scope) { $scope.latticeService = latticeService; $scope.tooltip = SIREPO.lattice.beamlineEditorTooltip; $scope.beamlineItems = []; @@ -687,7 +687,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel function cache(id) { if (itemCache[id] === undefined) { const res = latticeService.elementForId(id); - if (!res) { + if (! res) { throw new Error('Invalid element id: ' + id); } itemCache[id] = res; @@ -698,10 +698,10 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel $scope.itemCache = cache; function getPosition(idx) { - if (!activeBeamline.positions) { + if (! activeBeamline.positions) { activeBeamline.positions = []; } - if (!activeBeamline.positions[idx]) { + if (! activeBeamline.positions[idx]) { activeBeamline.positions[idx] = {}; } return activeBeamline.positions[idx]; @@ -766,7 +766,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel else { x = Math.round( (rpnService.getRpnValue(pos.elemedge) + rpnService.getRpnValue(el.l || 0)) - * 1e7) / 1e7; + * 1e7) / 1e7; } } getPosition(index).elemedge = x; @@ -782,7 +782,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel function setPosition(popupName, fields) { $scope.clearPopover(); - if (!latticeService.selectedItem) { + if (! latticeService.selectedItem) { return; } let idx = itemIndex(latticeService.selectedItem); @@ -821,7 +821,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel function showPopover(item, popoverName) { activePopoverName = popoverName; let info = $scope.popoverInfo[popoverName]; - if (!info.content) { + if (! info.content) { // keep a single reference to prevent garbage collection when dismissed? info.content = $('.' + info.class); } @@ -842,7 +842,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel function showPopoverForItem(item) { panelState.waitForUI(() => { - if (!item.isBeamline && latticeService.isAbsolutePositioning()) { + if (! item.isBeamline && latticeService.isAbsolutePositioning()) { panelState.waitForUI(() => showElementPositionPopover(item)); } }); @@ -871,7 +871,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel $scope.selectItem(item, $event); if (latticeService.isAbsolutePositioning()) { $('.sr-lattice-item').not(getUIItem(item)).popover('hide'); - if (!item.isBeamline) { + if (! item.isBeamline) { showElementPositionPopover(item); } } @@ -957,7 +957,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel }; $scope.dropItem = (index, data) => { - if (!data || dragCanceled) { + if (! data || dragCanceled) { return; } $scope.clearPopover(); @@ -993,7 +993,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel }; $scope.dropPanel = (data) => { - if (!data + if (! data || data.itemId || data.id == activeBeamline.id || dragCanceled) { @@ -1011,7 +1011,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel updateBeamline(false); dropHandled = false; panelState.waitForUI(() => { - if (!dropHandled) { + if (! dropHandled) { $rootScope.$broadcast('sr-beamlineDropItem', item, $scope.beamlineItems); updateBeamline(true); showPopoverForItem(item); @@ -1029,7 +1029,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel $scope.editItem = (item) => { if (item.isBeamline) { - if (!latticeService.isAbsolutePositioning()) { + if (! latticeService.isAbsolutePositioning()) { showModifyBeamlinePopover(item); } } @@ -1070,7 +1070,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel $scope.onMouseDown = (item, $event) => { // right mouse button if ($event.buttons == 2 && item.isBeamline) { - if (!latticeService.isAbsolutePositioning()) { + if (! latticeService.isAbsolutePositioning()) { showModifyBeamlinePopover(item, $event); } } @@ -1078,7 +1078,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel $scope.reverseBeamline = () => { $scope.clearPopover(); - if (!latticeService.selectedItem || !latticeService.selectedItem.isBeamline) { + if (! latticeService.selectedItem || ! latticeService.selectedItem.isBeamline) { return; } let item = latticeService.selectedItem; @@ -1092,7 +1092,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel if ($scope.shiftClickHandler) { $scope.shiftClickHandler()(latticeService.selectedItem, item); } - else if (!latticeService.isAbsolutePositioning()) { + else if (! latticeService.isAbsolutePositioning()) { lastSelectedItem = item; $scope.newBeamline = latticeService.getNextBeamline(); $('#sr-beamline-from-elements-dialog').modal('show'); @@ -1114,7 +1114,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel }; $scope.showEditor = () => { - if (!appState.isLoaded() || !latticeService.activeBeamlineId) { + if (! appState.isLoaded() || ! latticeService.activeBeamlineId) { return false; } let beamline = latticeService.getActiveBeamline(); @@ -1134,7 +1134,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel $scope.unpackBeamline = () => { $scope.clearPopover(); - if (!latticeService.selectedItem || !latticeService.selectedItem.isBeamline) { + if (! latticeService.selectedItem || ! latticeService.selectedItem.isBeamline) { return; } let idx = $scope.beamlineItems.indexOf(latticeService.selectedItem); @@ -1177,7 +1177,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel (e, beamlineIndex) => $scope.selectItem($scope.beamlineItems[beamlineIndex])); $scope.$on('sr-beamlineOrderChanged', reloadBeamlineItems); }, - link: function (scope, element) { + link: function(scope, element) { scope.element = $(element).find('.sr-lattice-editor-panel').first(); $document.on('keydown', scope.onKeyDown); scope.$on('$destroy', () => $document.off('keydown', scope.onKeyDown)); @@ -1185,7 +1185,7 @@ SIREPO.app.directive('beamlineEditor', function (appState, latticeService, panel }; }); -SIREPO.app.directive('elementPicker', function (latticeService) { +SIREPO.app.directive('elementPicker', function(latticeService) { return { restrict: 'A', scope: { @@ -1241,17 +1241,17 @@ SIREPO.app.directive('elementPicker', function (latticeService) {
`, - controller: function ($scope) { + controller: function($scope) { $scope.activeTab = 'basic'; $scope.allNames = $scope.controller.basicNames.concat($scope.controller.advancedNames).sort(); $scope.showTabs = $scope.controller.advancedNames.length > 0; - $scope.createElement = function (name) { + $scope.createElement = function(name) { // don't show the new editor until the picker panel is gone // the modal show/hide in bootstrap doesn't handle layered modals // and the browser scrollbar can be lost in some cases var picker = $('#' + $scope.id); - picker.on('hidden.bs.modal', function () { + picker.on('hidden.bs.modal', function() { picker.off(); if ($scope.controller.createElement) { $scope.controller.createElement(name); @@ -1267,7 +1267,7 @@ SIREPO.app.directive('elementPicker', function (latticeService) { }; }); -SIREPO.app.directive('parameterWithLattice', function (appState) { +SIREPO.app.directive('parameterWithLattice', function(appState) { return { restrict: 'A', scope: { @@ -1281,13 +1281,13 @@ SIREPO.app.directive('parameterWithLattice', function (appState) {
`, - controller: function ($scope, $element) { + controller: function($scope, $element) { var latticeScope, plotScope; var isNestedSVG = false; function updateLattice() { if ($scope.showLattice() && latticeScope && plotScope) { - if (!isNestedSVG) { + if (! isNestedSVG) { // nest the SVG so the "download as png" gets both images isNestedSVG = true; var svgs = $($element).find('svg'); @@ -1302,10 +1302,10 @@ SIREPO.app.directive('parameterWithLattice', function (appState) { } } - $scope.showLattice = function () { + $scope.showLattice = function() { if (appState.isLoaded()) { if (appState.applicationState()[$scope.modelName].includeLattice == '1') { - if (plotScope && !plotScope.onRefresh) { + if (plotScope && ! plotScope.onRefresh) { plotScope.onRefresh = updateLattice; } return true; @@ -1318,12 +1318,12 @@ SIREPO.app.directive('parameterWithLattice', function (appState) { return false; }; - $scope.$on('sr-latticeLinked', function (event) { + $scope.$on('sr-latticeLinked', function(event) { latticeScope = event.targetScope; event.stopPropagation(); updateLattice(); }); - $scope.$on('sr-plotLinked', function (event) { + $scope.$on('sr-plotLinked', function(event) { if (event.targetScope.focusPoints) { plotScope = event.targetScope; event.stopPropagation(); @@ -1333,7 +1333,7 @@ SIREPO.app.directive('parameterWithLattice', function (appState) { }; }); -SIREPO.app.directive('lattice', function (appState, latticeService, panelState, plotting, rpnService, utilities, $rootScope, $window) { +SIREPO.app.directive('lattice', function(appState, latticeService, panelState, plotting, rpnService, utilities, $rootScope, $window) { return { restrict: 'A', scope: { @@ -1344,7 +1344,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, showTable: '@', }, templateUrl: '/static/html/lattice.html' + SIREPO.SOURCE_CACHE_KEY, - controller: function ($scope) { + controller: function($scope) { let panTranslate = [0, 0]; let picTypeCache = null; let selectedBeamline = null; @@ -1383,7 +1383,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, function subScaleWatch() { var xsMax = 50; return { - x: ($scope.xScale > xsMax ? xsMax / $scope.xScale : 1), + x: ($scope.xScale > xsMax ? xsMax / $scope.xScale : 1), y: 1, }; } @@ -1486,17 +1486,17 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, exitEdge = 0; } var exit = [enter[0] + radius + Math.cos(angle) * radius, - pos.y + Math.sin(angle) * radius]; + pos.y + Math.sin(angle) * radius]; var exitAngle = exitEdge - angle; var points = [ - [enter[0] - Math.sin(-enterEdge) * height / 2, - enter[1] - Math.cos(-enterEdge) * height / 2], - [enter[0] + Math.sin(-enterEdge) * height / 2, - enter[1] + Math.cos(-enterEdge) * height / 2], - [exit[0] + Math.sin(exitAngle) * height / 2, - exit[1] + Math.cos(exitAngle) * height / 2], - [exit[0] - Math.sin(exitAngle) * height / 2, - exit[1] - Math.cos(exitAngle) * height / 2], + [enter[0] - Math.sin(-enterEdge) * height / 2, + enter[1] - Math.cos(-enterEdge) * height / 2], + [enter[0] + Math.sin(-enterEdge) * height / 2, + enter[1] + Math.cos(-enterEdge) * height / 2], + [exit[0] + Math.sin(exitAngle) * height / 2, + exit[1] + Math.cos(exitAngle) * height / 2], + [exit[0] - Math.sin(exitAngle) * height / 2, + exit[1] - Math.cos(exitAngle) * height / 2], ]; // trim overlap if necessary if (length >= 0) { @@ -1526,10 +1526,10 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, x += radius; newAngle = latticeService.radiansToDegrees(angle); pos.radius = radius; - if (item.type == 'CHANGREF' && !$scope.flatten) { + if (item.type == 'CHANGREF' && ! $scope.flatten) { adjustPosition(pos, item.XCE, -item.YCE); } - else if (item.type == 'CHANGREF_VALUE' && !$scope.flatten) { + else if (item.type == 'CHANGREF_VALUE' && ! $scope.flatten) { if (item.transformType == 'XS') { adjustPosition(pos, item.transformValue, 0); } @@ -1629,7 +1629,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, } } else if (picType == 'magnet') { - if (!length) { + if (! length) { groupItem.height = 0.2; groupItem.y = pos.y; groupItem.picType = 'zeroLength'; @@ -1668,7 +1668,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, groupItem.y = pos.y; //TODO(pjm): special zgoubi type, shift Y/Z axis 180 if (item.type == 'YMY') { - pos.inReverseBend = !pos.inReverseBend; + pos.inReverseBend = ! pos.inReverseBend; } } else if (picType == 'rf') { @@ -1736,7 +1736,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, if ($scope.flatten) { newAngle = 0; } - group.trackHash = $scope.svgGroups.length + ' ' + group.items.map(function (item) { + group.trackHash = $scope.svgGroups.length + ' ' + group.items.map(function(item) { return item.trackHash; }).join(' '); pos.angle += newAngle; @@ -1746,9 +1746,9 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, if (items.indexOf(id) >= 0) { return true; } - if (!beamlineCache) { + if (! beamlineCache) { beamlineCache = {}; - $scope.models.beamlines.forEach(function (b) { + $scope.models.beamlines.forEach(function(b) { beamlineCache[b.id] = b.items; }); } @@ -1775,8 +1775,8 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, function calculateInitialBeamlineMetrics() { // when lattice is initially loaded after import, calculate stats for all beamlines var beamlines = $scope.models.beamlines; - if (beamlines.length && !angular.isDefined(beamlines[0].count)) { - beamlines.forEach(function (beamline) { + if (beamlines.length && ! angular.isDefined(beamlines[0].count)) { + beamlines.forEach(function(beamline) { loadItemsFromBeamline(true, beamline); }); } @@ -1834,7 +1834,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, //TODO(pjm): will infinitely recurse if beamlines are self-referential function explodeItems(beamline, res, reversed, beamlineIndex) { var items = beamline.items; - if (!res) { + if (! res) { res = []; } if (reversed) { @@ -1879,7 +1879,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, } function getPicType(type) { - if (!picTypeCache) { + if (! picTypeCache) { picTypeCache = {}; var elementPic = SIREPO.lattice.elementPic; for (var picType in elementPic) { @@ -1925,11 +1925,11 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, beamline = beamline || ($scope.flatten && $scope.modelName != 'twissReport' ? latticeService.getSimulationBeamline() : latticeService.getActiveBeamline()); - if (!beamline) { + if (! beamline) { selectedBeamline = null; return; } - if (!forceUpdate && selectedBeamline + if (! forceUpdate && selectedBeamline && appState.deepEquals(beamline.items, selectedBeamline.items) && appState.deepEquals(beamline.positions, selectedBeamline.positions)) { return; @@ -1937,7 +1937,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, selectedBeamline = appState.clone(beamline); $scope.svgGroups = []; var pos = computePositions(); - if (!$scope.flatten && beamlineValue(beamline, 'distance', Math.sqrt(Math.pow(pos.x, 2) + Math.pow(pos.y, 2))) + if (! $scope.flatten && beamlineValue(beamline, 'distance', Math.sqrt(Math.pow(pos.x, 2) + Math.pow(pos.y, 2))) + beamlineValue(beamline, 'length', pos.length) + beamlineValue(beamline, 'angle', latticeService.degreesToRadians(pos.angle)) + beamlineValue(beamline, 'count', pos.count)) { @@ -2027,16 +2027,16 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, $scope.$broadcast('sr-renderBeamline'); } - $scope.destroy = function () { + $scope.destroy = function() { if (zoom) { zoom.on('zoom', null); } }; - $scope.init = function () { + $scope.init = function() { zoom = d3.behavior.zoom() .scaleExtent([1, 50]); - if (!$scope.flatten) { + if (! $scope.flatten) { zoom.on('zoom', zoomed); //TODO(pjm): call stopPropagation() on item double-click instead, would allow double-click zoom on empty space select('svg').call(zoom) @@ -2045,15 +2045,15 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, $scope.resize(); }; - $scope.itemClicked = function (item) { + $scope.itemClicked = function(item) { $rootScope.$broadcast('sr-beamlineItemSelected', item.beamlineIndex); }; - $scope.itemDblClicked = function (item) { + $scope.itemDblClicked = function(item) { latticeService.editElement(item.type, item, $scope.models); }; - $scope.resize = function () { + $scope.resize = function() { if (select().empty()) { return; } @@ -2100,8 +2100,8 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, } }; - $scope.updateFixedAxis = function (axis, leftMargin, yScale, height, yOffset) { - if (!axis.domain) { + $scope.updateFixedAxis = function(axis, leftMargin, yScale, height, yOffset) { + if (! axis.domain) { return; } var widthInPixels = axis.scale.range()[1]; @@ -2123,13 +2123,13 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, } // only show the loading message for simulations with a lot of elements $scope.isLoading = $scope.models.elements.length > 25; - panelState.waitForUI(function () { + panelState.waitForUI(function() { $scope.isLoading = false; loadItemsFromBeamline(forceUpdate); }); } - appState.whenModelsLoaded($scope, function () { + appState.whenModelsLoaded($scope, function() { function getModels() { $scope.models = $scope.pathToModels ? appState.models[$scope.pathToModels].models : appState.models; } @@ -2138,12 +2138,12 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, calculateInitialBeamlineMetrics(); renderBeamline(); - $scope.$on($scope.pathToModels + '.changed', function (e, name) { + $scope.$on($scope.pathToModels + '.changed', function(e, name) { getModels(); renderBeamline(true); }); - $scope.$on('modelChanged', function (e, name) { + $scope.$on('modelChanged', function(e, name) { if (name == 'beamlines') { renderBeamline(); } @@ -2159,7 +2159,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, $scope.$on('cancelChanges', getModels); - $scope.$on('activeBeamlineChanged', function ($event, updateNoWait) { + $scope.$on('activeBeamlineChanged', function($event, updateNoWait) { renderBeamline(false, updateNoWait); resetZoomAndPan(); }); @@ -2172,7 +2172,7 @@ SIREPO.app.directive('lattice', function (appState, latticeService, panelState, }; }); -SIREPO.app.directive('latticeBeamlineList', function (appState) { +SIREPO.app.directive('latticeBeamlineList', function(appState) { return { restrict: 'A', scope: { @@ -2183,22 +2183,22 @@ SIREPO.app.directive('latticeBeamlineList', function (appState) { template: ` `, - controller: function ($scope) { + controller: function($scope) { var list = [ { id: '', name: 'NOT SELECTED', }, ]; - $scope.beamlineList = function () { - if (!appState.isLoaded() || !$scope.model) { + $scope.beamlineList = function() { + if (! appState.isLoaded() || ! $scope.model) { return null; } if ($scope.isOptional) { list.length = 1; return list.concat(appState.models.beamlines); } - if (!$scope.model[$scope.field] + if (! $scope.model[$scope.field] && appState.models.beamlines && appState.models.beamlines.length) { $scope.model[$scope.field] = appState.models.beamlines[0].id; @@ -2209,7 +2209,7 @@ SIREPO.app.directive('latticeBeamlineList', function (appState) { }; }); -SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, panelState, $window) { +SIREPO.app.directive('latticeBeamlineTable', function(appState, latticeService, panelState, $window) { return { restrict: 'A', scope: {}, @@ -2257,7 +2257,7 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, `, - controller: function ($scope) { + controller: function($scope) { $scope.appState = appState; $scope.latticeService = latticeService; var windowSize = 0; @@ -2266,7 +2266,7 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, function computeNesting() { isNested = {}; - appState.models.beamlines.forEach(function (beamline) { + appState.models.beamlines.forEach(function(beamline) { computeNestingBeamline(beamline); }); } @@ -2276,20 +2276,20 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, return; } var activeBeamline = latticeService.getActiveBeamline(); - if (!activeBeamline || activeBeamline.id === beamline.id) { + if(! activeBeamline || activeBeamline.id === beamline.id) { isNested[beamline.id] = true; return; } - if (!blItems) { + if(! blItems) { blItems = beamline.items || []; } - if (blItems.indexOf(activeBeamline.id) >= 0) { + if(blItems.indexOf(activeBeamline.id) >= 0) { isNested[beamline.id] = true; return; } - for (var i = 0; i < blItems.length; i++) { + for(var i = 0; i < blItems.length; i++) { var nextItems = latticeService.elementForId(blItems[i]).items; - if (nextItems && computeNestingBeamline(beamline, nextItems)) { + if(nextItems && computeNestingBeamline(beamline, nextItems)) { isNested[beamline.id] = true; return; } @@ -2298,7 +2298,7 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, function itemsToString(items) { var res = '('; - if (!items.length) { + if (! items.length) { res += ' '; } for (var i = 0; i < items.length; i++) { @@ -2316,10 +2316,10 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, windowSize = $($window).width(); } - $scope.copyBeamline = function (beamline) { + $scope.copyBeamline = function(beamline) { var newBeamline = latticeService.getNextBeamline(); - for (var prop in beamline) { - if (prop != 'id' && prop != 'name' && prop != 'items') { + for(var prop in beamline) { + if(prop != 'id' && prop != 'name' && prop != 'items') { newBeamline[prop] = beamline[prop]; } } @@ -2328,14 +2328,14 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, panelState.showModalEditor('beamline'); }; - $scope.beamlineBend = function (beamline, defaultValue) { + $scope.beamlineBend = function(beamline, defaultValue) { if (angular.isDefined(beamline.angle)) { return latticeService.angleFormat(beamline.angle); } return defaultValue; }; - $scope.beamlineDescription = function (beamline) { + $scope.beamlineDescription = function(beamline) { if (descriptionCache[beamline.id]) { return descriptionCache[beamline.id]; } @@ -2344,26 +2344,26 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, return res; }; - $scope.beamlineDistance = function (beamline) { + $scope.beamlineDistance = function(beamline) { return latticeService.numFormat(beamline.distance, 'm'); }; - $scope.beamlineLength = function (beamline) { + $scope.beamlineLength = function(beamline) { return latticeService.numFormat(beamline.length, 'm'); }; - $scope.deleteBeamline = function (beamline) { + $scope.deleteBeamline = function(beamline) { latticeService.deleteElementPrompt('beamlines', beamline); }; - $scope.isActiveBeamline = function (beamline) { + $scope.isActiveBeamline = function(beamline) { if (latticeService.activeBeamlineId) { return latticeService.activeBeamlineId == beamline.id; } return false; }; - $scope.isLargeWindow = function () { + $scope.isLargeWindow = function() { return windowSize >= 1200; }; @@ -2371,16 +2371,16 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, return isNested[beamline.id]; }; - appState.whenModelsLoaded($scope, function () { - $scope.$on('beamlines.changed', function () { + appState.whenModelsLoaded($scope, function() { + $scope.$on('beamlines.changed', function() { computeNesting(); descriptionCache = {}; }); - $scope.$on('elements.changed', function () { + $scope.$on('elements.changed', function() { descriptionCache = {}; }); $scope.$on('activeBeamlineChanged', computeNesting); - $scope.$on('sr-window-resize', windowResize); + $scope.$on('sr-window-resize', windowResize); computeNesting(); windowResize(); }); @@ -2388,7 +2388,7 @@ SIREPO.app.directive('latticeBeamlineTable', function (appState, latticeService, }; }); -SIREPO.app.directive('latticeElementPanels', function (latticeService) { +SIREPO.app.directive('latticeElementPanels', function(latticeService) { return { restrict: 'A', scope: {}, @@ -2415,13 +2415,13 @@ SIREPO.app.directive('latticeElementPanels', function (latticeService) { `, - controller: function ($scope) { + controller: function($scope) { $scope.latticeService = latticeService; }, }; }); -SIREPO.app.directive('latticeElementTable', function (appState, latticeService, panelState, $rootScope) { +SIREPO.app.directive('latticeElementTable', function(appState, latticeService, panelState, $rootScope) { return { restrict: 'A', scope: {}, @@ -2468,7 +2468,7 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, `, - controller: function ($scope) { + controller: function($scope) { $scope.latticeService = latticeService; $scope.tree = []; var collapsedElements = {}; @@ -2476,8 +2476,8 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, function areAllExpanded() { if (appState.models.treeMap) { - for (const k in appState.models.treeMap) { - if (appState.models.treeMap[k]) { + for (const k in appState.models.treeMap){ + if (appState.models.treeMap[k]){ return false; } } @@ -2496,7 +2496,7 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, } function elementDescription(element) { - if (!element) { + if (! element) { return 'null'; } if (angular.isDefined(descriptionCache[element._id])) { @@ -2536,7 +2536,7 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, return res; } - function getCollapsedMap() { + function getCollapsedMap(){ const m = {}; $scope.tree.forEach((e) => { m[e.name] = e.isCollapsed; @@ -2545,15 +2545,15 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, } function scrollToElem(found) { - if (found) { + if (found){ panelState.waitForUI(() => { - $('.sr-search-target')[0].scrollIntoView({ block: 'center' }); + $('.sr-search-target')[0].scrollIntoView({block: 'center'}); }); } } function getIsCollapsed(elType) { - if (appState.models.treeMap) { + if (appState.models.treeMap){ return appState.models.treeMap[elType]; } return false; @@ -2563,8 +2563,8 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, $scope.tree = []; descriptionCache = {}; var category = null; - appState.applicationState().elements.forEach(function (element) { - if (!category || category.name != element.type) { + appState.applicationState().elements.forEach(function(element) { + if (! category || category.name != element.type) { category = { name: element.type, elements: [], @@ -2582,30 +2582,30 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, appState.saveQuietly('treeMap'); } - $scope.deleteElement = function (element) { + $scope.deleteElement = function(element) { latticeService.deleteElementPrompt('elements', element); }; - $scope.editElement = function (type, item) { + $scope.editElement = function(type, item) { var el = latticeService.elementForId(item._id); return latticeService.editElement(type, el); }; $scope.copyElement = el => latticeService.copyElement(el); - $scope.elementLength = function (element) { + $scope.elementLength = function(element) { return latticeService.numFormat(element.l, 'm'); }; $scope.findElement = (el) => { - if (!el) { + if (!el){ return; } let found = false; let foundIndex = null; $scope.tree.forEach((t, i) => { t.elements.forEach((e, j) => { - if (e.name.toLowerCase().startsWith(el.toLowerCase()) && el.length > 1) { + if (e.name.toLowerCase().startsWith(el.toLowerCase()) && el.length > 1){ foundIndex = i; $scope.tree[i].elements[j].isMarked = true; found = true; @@ -2613,7 +2613,7 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, $scope.tree[i].elements[j].isMarked = false; } }); - if (i == foundIndex) { + if (i == foundIndex){ $scope.tree[i].isCollapsed = false; } else { $scope.tree[i].isCollapsed = true; @@ -2625,29 +2625,29 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, scrollToElem(found); }; - $scope.toggleCategory = function (category) { - category.isCollapsed = !category.isCollapsed; + $scope.toggleCategory = function(category) { + category.isCollapsed = ! category.isCollapsed; collapsedElements[category.name] = category.isCollapsed; appState.models.treeMap = getCollapsedMap(); appState.saveChanges('treeMap'); }; $scope.toggleCollapseElems = () => { - $scope.areAllExpanded = !$scope.areAllExpanded; + $scope.areAllExpanded = ! $scope.areAllExpanded; $scope.tree.forEach(e => { - e.isCollapsed = !$scope.areAllExpanded; + e.isCollapsed = ! $scope.areAllExpanded; }); appState.models.treeMap = getCollapsedMap(); appState.saveChanges('treeMap'); }; - $scope.$on('modelChanged', function (e, name) { + $scope.$on('modelChanged', function(e, name) { if (name == 'elements') { loadTree(); } }); - $scope.$on('elementDeleted', function (e, name) { + $scope.$on('elementDeleted', function(e, name) { if (name == 'elements') { loadTree(); } @@ -2657,7 +2657,7 @@ SIREPO.app.directive('latticeElementTable', function (appState, latticeService, }; }); -SIREPO.app.directive('latticeTab', function (latticeService, panelState, utilities, $window) { +SIREPO.app.directive('latticeTab', function(latticeService, panelState, utilities, $window) { return { restrict: 'A', scope: { @@ -2714,7 +2714,7 @@ SIREPO.app.directive('latticeTab', function (latticeService, panelState, utiliti `, - controller: function ($scope) { + controller: function($scope) { $scope.reportId = Math.floor(Math.random() * Number.MAX_SAFE_INTEGER); $scope.latticeService = latticeService; @@ -2722,42 +2722,42 @@ SIREPO.app.directive('latticeTab', function (latticeService, panelState, utiliti return SIREPO.APP_SCHEMA.model.twissReport ? true : false; } - $scope.showTwissReportButton = function () { + $scope.showTwissReportButton = function() { if (hasTwissReport()) { var beamline = latticeService.getActiveBeamline(); return beamline && beamline.length != 0; } return false; }; - $scope.showTwissReport = function () { + $scope.showTwissReport = function() { if (utilities.isFullscreen()) { utilities.exitFullscreenFn().call(document); } var el = $('#sr-lattice-twiss-plot'); el.modal('show'); - el.on('shown.bs.modal', function () { + el.on('shown.bs.modal', function() { $scope.twissReportShown = true; $scope.$digest(); }); - el.on('hidden.bs.modal', function () { + el.on('hidden.bs.modal', function() { $scope.twissReportShown = false; el.off(); }); }; - $scope.twissReportTitle = function () { + $scope.twissReportTitle = function() { if (hasTwissReport()) { return SIREPO.APP_SCHEMA.view.twissReport.title; } return ''; }; - $scope.showTwissEditor = function () { + $scope.showTwissEditor = function() { panelState.showModalEditor('twissReport'); }; }, }; }); -SIREPO.app.directive('rpnBoolean', function (rpnService) { +SIREPO.app.directive('rpnBoolean', function(rpnService) { return { restrict: 'A', scope: { @@ -2767,15 +2767,15 @@ SIREPO.app.directive('rpnBoolean', function (rpnService) { template: ` `, - controller: function ($scope) { - $scope.rpnBooleanValues = function () { + controller: function($scope) { + $scope.rpnBooleanValues = function() { return rpnService.getRpnBooleanForField($scope.model, $scope.field); }; }, }; }); -SIREPO.app.directive('rpnStatic', function (rpnService) { +SIREPO.app.directive('rpnStatic', function(rpnService) { return { restrict: 'A', scope: { @@ -2787,8 +2787,8 @@ SIREPO.app.directive('rpnStatic', function (rpnService) { template: `
{{ computedRpnValue(); }}
`, - controller: function ($scope) { - $scope.computedRpnValue = function () { + controller: function($scope) { + $scope.computedRpnValue = function() { if ($scope.isBusy) { return 'calculating...'; } @@ -2800,7 +2800,7 @@ SIREPO.app.directive('rpnStatic', function (rpnService) { }; }); -SIREPO.app.directive('rpnEditor', function () { +SIREPO.app.directive('rpnEditor', function() { return { restrict: 'A', template: ` @@ -2811,26 +2811,26 @@ SIREPO.app.directive('rpnEditor', function () {
`, - controller: function ($scope) { + controller: function($scope) { $scope.isBusy = false; $scope.isError = false; }, }; }); -SIREPO.app.directive('rpnValue', function (appState, rpnService) { +SIREPO.app.directive('rpnValue', function(appState, rpnService) { var requestIndex = 0; return { restrict: 'A', require: 'ngModel', - link: function (scope, element, attrs, ngModel) { + link: function(scope, element, attrs, ngModel) { var rpnVariableName = scope.modelName == 'rpnVariable' ? scope.model.name : null; var range = { min: scope.info[4], max: scope.info[5], }; - scope.isRequired = function () { + scope.isRequired = function() { if (scope.info && scope.info[1] == 'OptionalRPNValue') { return false; } @@ -2842,7 +2842,7 @@ SIREPO.app.directive('rpnValue', function (appState, rpnService) { return true; }; - ngModel.$parsers.push(function (value) { + ngModel.$parsers.push(function(value) { scope.isError = false; requestIndex++; var currentRequestIndex = requestIndex; @@ -2866,21 +2866,21 @@ SIREPO.app.directive('rpnValue', function (appState, rpnService) { return v; } scope.isBusy = true; - rpnService.computeRpnValue(value, function (v, err) { + rpnService.computeRpnValue(value, function(v, err) { // check for a stale request if (requestIndex != currentRequestIndex) { return; } scope.isBusy = false; scope.isError = err ? true : false; - ngModel.$setValidity('', !scope.isError); - if (rpnVariableName && !err) { + ngModel.$setValidity('', ! scope.isError); + if (rpnVariableName && ! err) { rpnService.recomputeCache(rpnVariableName, v); } }); return value; }); - ngModel.$formatters.push(function (value) { + ngModel.$formatters.push(function(value) { if (ngModel.$isEmpty(value)) { return value; } @@ -2890,7 +2890,7 @@ SIREPO.app.directive('rpnValue', function (appState, rpnService) { }; }); -SIREPO.app.directive('varEditor', function (appState, latticeService, requestSender) { +SIREPO.app.directive('varEditor', function(appState, latticeService, requestSender) { return { scope: {}, template: ` @@ -2961,7 +2961,7 @@ SIREPO.app.directive('varEditor', function (appState, latticeService, requestSen `, - controller: function ($scope, $element) { + controller: function($scope, $element) { $scope.appState = appState; function initNewVar() { @@ -2974,12 +2974,12 @@ SIREPO.app.directive('varEditor', function (appState, latticeService, requestSen } function nameExists(name) { - return appState.models.rpnVariables.map(function (v) { + return appState.models.rpnVariables.map(function(v) { return v.name; }).indexOf(name) >= 0; } - $scope.addVar = function () { + $scope.addVar = function() { if ($scope.hasNewVar()) { var name = $scope.newVar.name; if (nameExists(name)) { @@ -2994,20 +2994,20 @@ SIREPO.app.directive('varEditor', function (appState, latticeService, requestSen } }; - $scope.cancelChanges = function () { + $scope.cancelChanges = function() { $('#sr-variables').modal('hide'); appState.cancelChanges('rpnVariables'); appState.cancelChanges('rpnCache'); initNewVar(); }; - $scope.deleteVar = function (idx) { + $scope.deleteVar = function(idx) { var v = appState.models.rpnVariables[idx]; requestSender.sendRpn( appState, - function (data) { + function(data) { latticeService.deleteVarWarning = ''; - if (!appState.isLoaded()) { + if (! appState.isLoaded()) { return; } if (data.error) { @@ -3024,7 +3024,7 @@ SIREPO.app.directive('varEditor', function (appState, latticeService, requestSen }); }; - $scope.hasNewVar = function () { + $scope.hasNewVar = function() { return 'name' in $scope.newVar && 'value' in $scope.newVar && $scope.newVar.name !== '' @@ -3035,7 +3035,7 @@ SIREPO.app.directive('varEditor', function (appState, latticeService, requestSen && $scope.newVar.value !== undefined; }; - $scope.saveChanges = function () { + $scope.saveChanges = function() { $('#sr-variables').modal('hide'); if ($scope.hasNewVar()) { $scope.addVar(); @@ -3049,16 +3049,16 @@ SIREPO.app.directive('varEditor', function (appState, latticeService, requestSen }; }); -SIREPO.app.directive('varName', function (latticeService) { +SIREPO.app.directive('varName', function(latticeService) { return { restrict: 'A', require: 'ngModel', scope: {}, - link: function (scope, element, attrs, ngModel) { + link: function(scope, element, attrs, ngModel) { var latticeNames; function isElementOrCommandName(value) { - if (!latticeNames) { + if (! latticeNames) { latticeNames = {}; for (var m in SIREPO.APP_SCHEMA.model) { if (latticeService.isElementModelName(m)) { @@ -3072,11 +3072,11 @@ SIREPO.app.directive('varName', function (latticeService) { return latticeNames[value.toLowerCase()]; } - ngModel.$parsers.push(function (value) { - if (ngModel.$isEmpty(value)) { + ngModel.$parsers.push(function(value) { + if (ngModel.$isEmpty(value)) { return null; } - if (!value.match(/^[A-Z][A-Z0-9_.]*$/i)) { + if (! value.match(/^[A-Z][A-Z0-9_.]*$/i)) { return undefined; } if ((SIREPO.APP_SCHEMA.constants.latticeKeywords || []).includes(value.toLowerCase())) { @@ -3096,7 +3096,7 @@ SIREPO.app.directive('varName', function (latticeService) { $(document).on('show.bs.modal', '.modal', function () { var zIndex = 1040 + (10 * $('.modal:visible').length); $(this).css('z-index', zIndex); - setTimeout(function () { + setTimeout(function() { $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'); }, 0); }); From 4d921f89cbad85f46fd817254d0f0c8ae72bd853 Mon Sep 17 00:00:00 2001 From: moellep Date: Fri, 16 Jun 2023 21:10:13 +0000 Subject: [PATCH 68/68] added _MAX_H5_READ_TRIES constant and fixed missing crystal plots --- sirepo/template/silas.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sirepo/template/silas.py b/sirepo/template/silas.py index a4099622d3..0092b3c080 100644 --- a/sirepo/template/silas.py +++ b/sirepo/template/silas.py @@ -21,6 +21,7 @@ _CRYSTAL_CSV_FILE = "crystal.csv" _RESULTS_FILE = "results{}.h5" _CRYSTAL_FILE = "crystal{}.h5" +_MAX_H5_READ_TRIES = 3 def background_percent_complete(report, run_dir, is_running): @@ -162,7 +163,7 @@ def _frames(element, data): _initial_intensity_percent_complete(run_dir, res, data, ("beamlineAnimation0",)) count = PKDict( watch=1, - crystal=0, + crystal=1, ) total_count = 1 for e in data.models.beamline: @@ -436,8 +437,7 @@ def _z_label(plot_type): excited_states="Number [1/m³]", )[plot_type] - tries = 3 - for _ in range(tries): + for _ in range(_MAX_H5_READ_TRIES): try: with h5py.File( run_dir.join(_fname(element).format(element_index)), "r" @@ -456,7 +456,7 @@ def _z_label(plot_type): [ PKDict( points=y, - label=_label(plot_type), + label=_label(plot_type, 0), ), ], PKDict(),