Application PseudoCode - radiasoft/sirepo GitHub Wiki
Pseudocode for parts of the SRW application.
//---- file: srw-view.json (or yml or ...)
// view schema much as before, with additional static info (ex. plotType)
// or arbitrary constants, (ex. fluxPerUnitSurfaceTitle)
// the view schema could be kept separately from the model info which isn't
// needed by the server logic
// ex. view schema
{
fluxAnimation: {
title: "Spectral Flux",
fluxPerUnitSurfaceTitle: "Spectral Flux per Unit Surface for Finite Emittance Electron Beam",
plotType: "parameter",
advanced: [
["Main", [
"distanceFromSource",
"initialEnergy",
"finalEnergy",
"photonEnergyPointCount",
"numberOfMacroElectronsAvg",
"savingPeriodicity",
[
["Horizontal", [
"horizontalApertureSize",
"horizontalPosition"
]],
["Vertical", [
"verticalApertureSize",
"verticalPosition"
]]
],
"fluxType",
"polarization",
"plotScale",
"notes"
]],
["Accuracy", [
"magneticField",
"method",
"precision",
"numberOfMacroElectrons",
"initialHarmonic",
"finalHarmonic",
"longitudinalPrecision",
"azimuthalPrecision"
]]
]
},
...
}
//---- file: srw.js
from enum import Flux, SourceType
// saved is the saved model state
// (appState.applicationState() in the current app)
// ex. saved.simulation is appState.applicationState().simulation
import saved
import util
// application specific business logic, similar to srwService
srw = {
fluxTitle: panel => {
// panel is an Panel instance (ReportPanel, EditorPanel, etc)
// panel.model is a model instance
// panel.title and other attrs come from view info in schema
return self.titleWithPosition(
panel,
panel.model.fluxType == Flux.PerUnitSurface
? panel.fluxPerUnitSurfaceTitle
: panel.title
);
},
titleWithPosition: (panel, title) =>
"{title || panel.title} "
+ util.formatNumberWithUnits(panel.model, 'distanceFromSource');
};
app.addTabContent(
'source',
// panel instances would be EditorPanel or ReportPanel based on the model type
panels: [
'electronBeam',
'arbitraryMagField',
'undulator',
'tabulatedUndulator',
'multipole',
'gaussianBeam',
'intensityReport',
'trajectoryReport',
'fluxReport',
'fluxAnimation',
'powerDensityReport',
'sourceIntensityReport',
'brillianceReport',
],
);
app.addTabContent(
'beamline',
Join([
BeamlineToolbar(),
BeamlineBuilder({
leftButton: ModalEditorButton('simulationGrid'),
rightButton: ModalEditorButton('propagationParameters'),
}),
Tabs([
Tab('single', BeamlineAnimationPanels()),
Tab('multi', Panels(
ReportPanel('multiElectronAnimation'),
If(() => saved.multiElectronAnimation.calcCoherence, [
ReportPanel('coherenceXAnimation'),
ReportPanel('coherenceYAnimation'),
]),
)),
Tab('beamline3d', ReportPanel('beamline3DReport')),
]),
]),
);
//--- file srw/undulatorView.js
import io
// "model" are schema models which are being edited, may be canceled
// (appState.models in the current app)
// ex. model.simulation is appState.models.simulation
from model import undulator
import saved
import ui
import util
import view
// view business logic, implementation is tied to schema view name
view.addView('undulator', {
// private methods with leading underscore
_compute: (undulatorDef, direction) => {
const d = "{direction}DeflectionParameter";
const a = "{direction}Amplitude";
io.sendStatelessCompute(
{
method: 'process_undulator_definition',
undulator_definition: undulatorDef,
undulator_parameter: undulator[d],
amplitude: undulator[a],
undulator_period: undulator.period / 1000,
methodSignature: 'process_undulator_definition' + d,
}
(reply) => {
if (undulatorDef == 'K') {
undulator[a] = reply.amplitude;
}
else if (undulatorDefinition === 'B') {
undulator[d] = reply.undulator_parameter;
}
undulator.effectiveDeflectingParameter = util.formatNumber(
Math.sqrt(
Math.pow(undulator.horizontalDeflectingParameter, 2) +
Math.pow(undulator.verticalDeflectingParameter, 2)
),
8,
);
},
);
_updateUndulator: () => {
if (ui.isActiveField('undulator.horizontalAmplitude')) {
_compute('B', 'horizontal');
}
elif (ui.isActiveField('undulator.verticalAmplitude')) {
_compute('B', 'vertical');
}
elif (ui.isActiveField('undulator.period')) {
_compute('B', 'horizontal');
_compute('B', 'vertical');
}
elif (ui.isActiveField('undulator.horizontalDeflectingParameter')) {
_compute('K', 'horizontal');
}
elif (ui.isActiveField('undulator.verticalDeflectingParameter')) {
_compute('K', 'vertical');
}
},
// could also have special methods for computed titles, ex. panelTitle()
showPanel: () => saved.simulation.sourceType.isIdealizedUndulator(),
// or the same thing:
showPanel: saved.simulation.sourceType.isIdealizedUndulator,
whenShown: () => {
ui.enableField('undulator.effectiveDeflectingParameter', false);
},
watchFields: [
((
'undulator.horizontalDeflectingParameter',
'undulator.verticalDeflectingParameter'
'undulator.horizontalAmplitude',
'undulator.verticalAmplitude',
'undulator.period',
), _updateUndulator),
],
});