-
Notifications
You must be signed in to change notification settings - Fork 32
Hello World Application
Let's add a new sirepo app, named "myapp". Full source for the application can be found in the master sirepo branch.
First, create the schema for the application. The myapp schema contains a model named "dog" with a few basic attributes.
sirepo/package_data/static/json/myapp-schema.json
{
"dynamicFiles": {
"sirepoLibs": {
"js": ["myapp.js"]
}
},
"localRoutes": {
"source": {
"config": {
"controller": "MyAppSourceController as source",
"templateUrl": "/static/html/myapp-source.html"
}
}
},
"enum": {
"Gender": [
["male", "Male"],
["female", "Female"]
],
"DogDisposition": [
["aggressive", "Aggressive"],
["friendly", "Friendly"],
["submissive", "Submissive"]
]
},
"model": {
"dog": {
"breed": ["Breed", "String"],
"gender": ["Gender", "Gender", "male"],
"height": ["Height [cm]", "Float", 50.0, "Distance from front paws to withers"],
"weight": ["Weight [lbs]", "Float", 60.5],
"disposition": ["Disposition", "DogDisposition", "friendly"],
"favoriteTreat": ["Favorite Treat", "OptionalString", ""]
},
"heightWeightReport": {}
},
"view": {
"dog": {
"title": "Dog",
"basic": [
"breed",
"weight",
"height",
"disposition",
"favoriteTreat"
],
"advanced": [
"breed",
"gender",
"weight",
"height"
]
},
"heightWeightReport": {
"title": "Physical Characteristics",
"advanced": []
}
}
}
When a new simulation is created, the default-data.json file contains the initial values.
sirepo/package_data/template/myapp/default-data.json
{
"models": {
"dog": {
"breed": "Labrador Retriever",
"gender": "female"
},
"simulation": {}
},
"simulationType": "myapp"
}
Next we'll need the javascript application which contains an angularjs controller for the source page and the application header.
sirepo/package_data/static/js/myapp.js
'use strict';
var srlog = SIREPO.srlog;
var srdbg = SIREPO.srdbg;
SIREPO.app.controller('MyAppSourceController', function (appState, panelState, $scope) {
var self = this;
function handleDogDisposition() {
panelState.showField('dog', 'favoriteTreat', appState.models.dog.disposition == 'friendly');
}
appState.whenModelsLoaded($scope, function() {
// after the model data is available, hide/show the
// favoriteTreat field depending on the disposition
handleDogDisposition();
appState.watchModelFields($scope, ['dog.disposition'], function() {
// respond to changes in the disposition field value
handleDogDisposition();
});
});
});
SIREPO.app.directive('appFooter', function() {
return {
restrict: 'A',
scope: {
nav: '=appFooter',
},
template: [
'<div data-common-footer="nav"></div>',
].join(''),
};
});
SIREPO.app.directive('appHeader', function(appState, panelState) {
return {
restrict: 'A',
scope: {
nav: '=appHeader',
},
template: [
'<div data-app-header-brand="nav"></div>',
'<div data-app-header-left="nav"></div>',
'<div data-app-header-right="nav">',
'<app-header-right-sim-loaded>',
'<div data-sim-sections="">',
'<li class="sim-section" data-ng-class="{active: nav.isActive(\'source\')}"><a href data-ng-click="nav.openSec\
tion(\'source\')"><span class="glyphicon glyphicon-flash"></span> Source</a></li>',
'</div>',
'</app-header-right-sim-loaded>',
'<app-settings>',
// '<div>App-specific setting item</div>',
'</app-settings>',
'<app-header-right-sim-list>',
'</app-header-right-sim-list>',
'</div>',
].join(''),
};
});
The myapp.js refers to the myapp-source.html file for the definition of the "Source" page.
sirepo/package_data/static/html/myapp-source.html
<div class="container-fluid">
<div class="row">
<div class="col-md-6">
<div data-basic-editor-panel="" data-view-name="dog"></div>
</div>
<div class="col-md-6">
<div data-report-panel="parameter" data-model-name="heightWeightReport"></div>
</div>
</div>
</div>
The myapp-source.html will arrange the dog editor and report.
The server components are comprised of the application code generator (template/myapp.py) and the executor (pkcli/myapp.py).
sirepo/template/myapp.py
# -*- coding: utf-8 -*-
u"""Myapp execution template.
:copyright: Copyright (c) 2017-2018 RadiaSoft LLC. All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from __future__ import absolute_import, division, print_function
from pykern import pkcollections
from pykern import pkio
from pykern import pkjinja
from pykern.pkdebug import pkdc, pkdp
from sirepo import simulation_db
from sirepo.template import template_common
import copy
SIM_TYPE = 'myapp'
INPUT_NAME = 'hundli.yml'
OUTPUT_NAME = 'hundli.csv'
_SCHEMA = simulation_db.get_schema(SIM_TYPE)
def fixup_old_data(data):
for m in _SCHEMA.model:
if m not in data.models:
data.models[m] = pkcollections.Dict({})
template_common.update_model_defaults(data.models[m], m, _SCHEMA)
def get_data_file(run_dir, model, frame, options=None):
f = run_dir.join(OUTPUT_NAME)
return f.basename, f.read(), 'text/csv'
def lib_files(data, source_lib):
return []
def models_related_to_report(data):
r = data['report']
return [
r,
'dog',
]
def python_source_for_model(data, model):
return _generate_parameters_file(data)
def write_parameters(data, run_dir, is_parallel):
pkio.write_text(
run_dir.join(template_common.PARAMETERS_PYTHON_FILE),
_generate_parameters_file(data),
)
def _generate_parameters_file(data):
if 'report' in data:
assert data['report'] == 'heightWeightReport', \
'unknown report: {}'.format(data['report'])
v = copy.deepcopy(data['models'], pkcollections.Dict())
v.input_name = INPUT_NAME
v.output_name = OUTPUT_NAME
return template_common.render_jinja(
SIM_TYPE,
v,
template_common.PARAMETERS_PYTHON_FILE,
)
sirepo/pkcli/myapp.py
# -*- coding: utf-8 -*-
"""Wrapper to run myapp from the command line.
:copyright: Copyright (c) 2017 RadiaSoft LLC. All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from __future__ import absolute_import, division, print_function
from pykern import pkio
from pykern import pksubprocess
from pykern.pkdebug import pkdp, pkdc, pkdlog
from sirepo import simulation_db
from sirepo.template import template_common
import csv
import sirepo.template.myapp as template
import sys
_SCHEMA = simulation_db.get_schema(template.SIM_TYPE)
def run(cfg_dir):
with pkio.save_chdir(cfg_dir):
try:
pksubprocess.check_call_with_signals(
[sys.executable, template_common.PARAMETERS_PYTHON_FILE],
)
except Exception as e:
pkdlog('script failed: dir={} err={}', cfg_dir, e)
simulation_db.write_result({
'error': 'program error occured',
})
return
data = simulation_db.read_json(template_common.INPUT_BASE_NAME)
if data.report == 'heightWeightReport':
res = _report(
'Dog Height and Weight Over Time',
('height', 'weight'),
data,
)
else:
raise AssertionError('unknown report: {}'.format(data.report))
simulation_db.write_result(res)
def _csv_to_cols():
with open(template.OUTPUT_NAME, 'r') as f:
rows = csv.reader(f)
headers = rows.next()
cols = [[] for _ in headers]
for row in rows:
for i, c in enumerate(row):
cols[i].append(float(c))
return dict((k.lower(), cols[i]) for i, k in enumerate(headers))
def _label(field):
return _SCHEMA.model.dog[field][0]
def _plot(dog, field, cols):
return {
'name': field,
'label': _label(field),
'points': cols[field],
}
def _report(title, fields, data):
dog = data.models.dog
cols = _csv_to_cols()
x_points = cols['year']
plots = [_plot(dog, f, cols) for f in fields]
return {
'title': title,
'x_range': [x_points[0], x_points[-1]],
'y_label': _label(fields[0]) if len(fields) == 1 else '',
'x_label': 'Age (years)',
'x_points': x_points,
'plots': plots,
'y_range': template_common.compute_plot_color_and_range(plots),
}
Now the application is ready to be added to the sirepo configuration files:
sirepo/feature_config.py
...
#: Codes on dev and alpha:
_NON_PROD_FOSS_CODES = frozenset(('myapp', ))
sirepo/package_data/static/json/schema-common.json
"appInfo": {
"myapp": {
"longName": "MyApp",
"shortName": "MyApp"
},
...
The app is ready to run. Start the sirepo server from the command line:
$ sirepo service http
Then open your web browser http://localhost:8000/myapp
License: http://www.apache.org/licenses/LICENSE-2.0.html
Copyright ©️ 2015–2020 RadiaSoft LLC. All Rights Reserved.
- Activait
- Controls
- elegant
- FLASH
- Genesis
- JSPEC
- JupyterHub
- MAD-X
- OPAL
- Radia
- Shadow
- Synchrotron Radiation Workshop (SRW)
- Warp PBA
- Warp VND
- Zgoubi
- Authentication and Account Creation
- How Your Sirepo Workspace Works
- Navigating the Sirepo Simulations Interface
- How to upload a lattice file
- How to share a Sirepo simulation via URL
- How Example simulations work
- How to report a bug in Sirepo
- Using lattice files in Sirepo
- Resetting an Example Simulation to default
- Backup SRW Sirepo simulations
- SRW Aperture
- SRW Brilliance Report
- SRW Circular Cylinder Mirror
- SRW CRL
- SRW Crystal
- SRW Electron Beam
- SRW Elliptical Cylinder Mirror
- SRW Fiber
- SRW Flux
- SRW Fully Coherent Gaussian Beam
- SRW Import Python or JSON Simulation File
- SRW Initial Wavefront Simulation Grid
- SRW Intensity Report
- SRW Planar Mirror
- SRW Power Density Report
- SRW Propagation Parameters
- SRW Single Electron Spectrum Report
- SRW Spherical Mirror
- SRW Toroid Mirror
- SRW Watchpoint
- SRW Additional Documentation