diff --git a/sirepo/package_data/static/html/silas-thermal-transport.html b/sirepo/package_data/static/html/silas-thermal-transport.html index ff5e7fdd8d..28778ae096 100644 --- a/sirepo/package_data/static/html/silas-thermal-transport.html +++ b/sirepo/package_data/static/html/silas-thermal-transport.html @@ -18,5 +18,8 @@
+
+
+
diff --git a/sirepo/package_data/static/js/silas.js b/sirepo/package_data/static/js/silas.js index 836ab5a4d0..40f8b5b3a2 100644 --- a/sirepo/package_data/static/js/silas.js +++ b/sirepo/package_data/static/js/silas.js @@ -5,11 +5,7 @@ var srdbg = SIREPO.srdbg; SIREPO.app.config(function() { SIREPO.INITIAL_INTENSITY_REPORT_TITLE = 'Initial Laser Pulse'; - SIREPO.SINGLE_FRAME_ANIMATION = [ - 'plotAnimation', - 'plot2Animation', - 'crystal3dAnimation', - ]; + SIREPO.SINGLE_FRAME_ANIMATION = []; SIREPO.appFieldEditors += `
@@ -50,7 +46,7 @@ SIREPO.app.factory('silasService', function(appState) { const self = {}; self.computeModel = (analysisModel) => { - if (['crystalAnimation', 'crystal3dAnimation', 'plotAnimation', 'plot2Animation', 'tempHeatMapAnimation', 'tempProfileAnimation'].indexOf(analysisModel) >= 0) { + if (['crystalAnimation', 'crystal3dAnimation', 'tempHeatMapAnimation', 'tempProfileAnimation'].indexOf(analysisModel) >= 0) { return 'crystalAnimation'; } if (['laserPulseAnimation', 'laserPulse2Animation'].includes(analysisModel)) { @@ -189,14 +185,6 @@ SIREPO.app.controller('CrystalController', function (appState, frameCache, persi self.simState = persistentSimulation.initSimulationState(self); self.simState.errorMessage = () => errorMessage; - - appState.whenModelsLoaded($scope, () => { - $scope.$on('plotAnimation.summaryData', function (e, data) { - if (data.crystalLength && data.crystalLength != silasService.getThermalCrystal().length) { - frameCache.setFrameCount(0); - } - }); - }); }); SIREPO.app.directive('appFooter', function(appState, silasService) { @@ -677,11 +665,12 @@ SIREPO.app.directive('crystal3d', function(appState, plotting, silasService, plo let len = []; let indices = []; let verts = data.vertices; + const c = appState.applicationState().thermalTransportCrystal.crystal; let size = $scope.boundAxis == 'Z' - ? silasService.getThermalCrystal().length - : appState.applicationState().thermalTransportCrystal.crystal.inversion_mesh_extent * 2; + ? c.length + : c.inversion_mesh_extent * 2 * 100; let axisIdx = $scope.axes.indexOf($scope.boundAxis); - $scope.bound = (size + 0.01) * ($scope.sliderValue - 50) / 100; + $scope.bound = (size + 0.01) * $scope.sliderValue / 100 - size / 2; for (let i = 0; i < data.indices.length; i += 3) { if (checkBounds(i, axisIdx)) { indices.push(data.indices[i], data.indices[i + 1], data.indices[i + 2]); @@ -732,7 +721,6 @@ SIREPO.app.directive('crystal3d', function(appState, plotting, silasService, plo camera.setFocalPoint(0, 0, 0); camera.setViewUp(0, -1, 0); renderer.resetCamera(); - camera.zoom(1.3); orientationMarker.updateMarkerOrientation(); } fsRenderer.getRenderWindow().render(); diff --git a/sirepo/package_data/static/json/silas-schema.json b/sirepo/package_data/static/json/silas-schema.json index 1bc74212e9..fc4d644715 100644 --- a/sirepo/package_data/static/json/silas-schema.json +++ b/sirepo/package_data/static/json/silas-schema.json @@ -149,7 +149,7 @@ "x": ["Horizontal Value to Plot", "ValueList", "x"], "y1": ["Vertical Value to Plot", "ValueList", "y"], "histogramBins": ["Histogram Bins", "Integer", 200], - "colorMap": ["Color Map", "ColorMap", "afmhot"] + "colorMap": ["Color Map", "ColorMap", "viridis"] }, "crystal3dAnimation": {}, "laserPulse": { @@ -192,8 +192,6 @@ "_super": ["_", "model", "beamElement"], "title": ["Element Name", "String", "Mirror"] }, - "plotAnimation": {}, - "plot2Animation": {}, "simulation": { "distanceFromSource": ["", "Float", 0.0 , "", 0.0] }, @@ -297,7 +295,8 @@ }, "crystal3dAnimation": { "title": "Crystal 3D Mesh", - "advanced": [] + "advanced": [], + "canFullScreen": false }, "mirror2": { "title": "Two Mirrors", @@ -364,14 +363,6 @@ "focalLength" ] }, - "plotAnimation": { - "title": "Radial Temperature Profile", - "advanced": [] - }, - "plot2Animation": { - "title": "Longitudinal Temperature Profile", - "advanced": [] - }, "n0n2Plot": { "title": "", "advanced": [] diff --git a/sirepo/package_data/template/silas/crystal.py.jinja b/sirepo/package_data/template/silas/crystal.py.jinja index 2ffe1c4ccc..3e7c37d9eb 100644 --- a/sirepo/package_data/template/silas/crystal.py.jinja +++ b/sirepo/package_data/template/silas/crystal.py.jinja @@ -10,32 +10,31 @@ crystal = Crystal(params=PKDict({{crystalParams}})) sim_type = "{{ thermalCrystal.calc_type }}" def thermo_optic_sim(): - thermo = ThermoOptic(crystal, {{thermalCrystal.mesh_density}}) + def _solve(): + if sim_type == "analytical": + return thermo.{{ pump_pulse_profile }}_solution() - # Initialize a simulator with a crystal object set - # Set evaluation points & boundary conditions + elif sim_type == "fenics": + thermo.set_boundary(2*(crystal.radius*100.)**2./40.) + thermo.set_load('{{ pump_pulse_profile }}') + r = crystal.params.pop_inversion_pump_rep_rate + if r <= 1: + return thermo.slow_solution('{{ pump_pulse_profile }}') + elif r >= 100: + return thermo.solve_steady() + else: + raise AssertionError(f"Invalid rep rate for simulated solve heat_load={'{{ pump_pulse_profile }}'}") + + thermo = ThermoOptic(crystal, {{ thermalCrystal.mesh_density }}) + + # prep for 2d solve thermo.set_points(( {{thermalTransportSettings_grid_points_r}}, {{thermalTransportSettings_grid_points_w}}, {{thermalTransportSettings_grid_points_z}}, - ), {{thermalTransportSettings_edge_fraction}}) - thermo.set_boundary(2*(crystal.radius*100.)**2./40.) - - if sim_type == "analytical": - Ts = thermo.{{ pump_pulse_profile }}_solution() + )) + res_2d = _solve() - elif sim_type == "fenics": - thermo.set_load('{{ pump_pulse_profile }}') - r = crystal.params.pop_inversion_pump_rep_rate - if r <= 1: - Ts = thermo.slow_solution('{{ pump_pulse_profile }}') - elif r >= 100: - Ts = thermo.solve_steady() - else: - raise AssertionError(f"Invalid rep rate for simulated solve heat_load={'{{ pump_pulse_profile }}'}") - - nT, n0Fit, n2Fit = thermo.compute_indices(Ts) - # Positions of each evaluation point & sets of the unique values ptzs = thermo.eval_pts[:, 2] ptrs = (thermo.eval_pts[:, 0] ** 2 + thermo.eval_pts[:, 1] ** 2) ** 0.5 zs = unique(ptzs) @@ -44,37 +43,38 @@ def thermo_optic_sim(): zface = zs.min() if crystal.params.pop_inversion_pump_type != "right" else zs.max() # Radial values reflected across axis & meshgrid with longitudinal values - rrs = array((-rs[::-1]).tolist() + rs[1:].tolist()) - RZ, ZR = meshgrid(rrs, zs) temp_profile = PKDict( - radial=[rs, Ts[ptzs==zface]], - longitudinal=[zs, Ts[ptrs==rcenter]] + radial=[rs, res_2d[ptzs==zface]], + longitudinal=[zs, res_2d[ptrs==rcenter]] ) - pTs = Ts.reshape((len(rs), len(zs)), order='F') + pTs = res_2d.reshape((len(rs), len(zs)), order='F') pTs = array((pTs[::-1]).tolist()+pTs[1:].tolist()) - heat_map = pTs + + # prep for 3d solve + mesh = thermo.mesh + inds = [] + for item in dolfin.cpp.mesh.facets(mesh): + inds.append(item.entities(0).tolist()) + vertices = mesh.coordinates() + thermo.eval_pts = vertices + res_3d = _solve() return PKDict( thermo=thermo, - heat_map=heat_map, + heat_map=pTs, temp_profile=temp_profile, - nT=nT, - n0Fit=n0Fit, - n2Fit=n2Fit, + intensity=res_3d, + vertices=vertices, + indices=numpy.array(inds), ) res = thermo_optic_sim() -# for 3D plots, get the facets, and build an array -# containing the indices of their coordinates -inds = [] -for item in dolfin.cpp.mesh.facets(res.thermo.mesh): - inds.append(item.entities(0).tolist()) # we will provide these indices to plotly so it can draw proper surfaces -inds = numpy.array(inds) -numpy.save("indices.npy", inds) -numpy.save("vertices.npy", res.thermo.mesh.coordinates()) +numpy.save("indices.npy", res.indices) +numpy.save("intensity.npy", res.intensity) +numpy.save("vertices.npy", res.vertices) template_common.write_dict_to_h5( res.temp_profile, "tempProfile.h5" diff --git a/sirepo/package_data/template/silas/examples/bella.json b/sirepo/package_data/template/silas/examples/bella.json index e8530a07d5..f060d08514 100644 --- a/sirepo/package_data/template/silas/examples/bella.json +++ b/sirepo/package_data/template/silas/examples/bella.json @@ -612,11 +612,8 @@ "reportType": "3d", "watchpointPlot": "total_intensity" }, - "plot2Animation": {}, - "plotAnimation": {}, "simulation": { "distanceFromSource": 0, - "documentationUrl": "", "folder": "/Examples", "name": "100TW amplifier with 3 crystals" } diff --git a/sirepo/package_data/template/silas/examples/multiple-pass-single-crystal.json b/sirepo/package_data/template/silas/examples/multiple-pass-single-crystal.json index b61a33c232..b22b747cce 100644 --- a/sirepo/package_data/template/silas/examples/multiple-pass-single-crystal.json +++ b/sirepo/package_data/template/silas/examples/multiple-pass-single-crystal.json @@ -318,12 +318,9 @@ "sigy_waist": 0.003056, "wfs": "" }, - "plot2Animation": {}, - "plotAnimation": {}, "simulation": { "distanceFromSource": 0, "folder": "/Examples", - "isExample": true, "name": "Multiple Passes Through Single Crystal" } }, diff --git a/sirepo/package_data/template/silas/examples/single-crystal.json b/sirepo/package_data/template/silas/examples/single-crystal.json index 9e8024448a..94f82dc55c 100644 --- a/sirepo/package_data/template/silas/examples/single-crystal.json +++ b/sirepo/package_data/template/silas/examples/single-crystal.json @@ -67,12 +67,9 @@ "sigy_waist": 0.001, "wfs": "" }, - "plot2Animation": {}, - "plotAnimation": {}, "simulation": { "distanceFromSource": 0, "folder": "/Examples", - "isExample": true, "name": "Single Crystal" }, "watchpointReport3": { diff --git a/sirepo/sim_data/silas.py b/sirepo/sim_data/silas.py index 97e4180a5a..2683549219 100644 --- a/sirepo/sim_data/silas.py +++ b/sirepo/sim_data/silas.py @@ -65,8 +65,6 @@ def _compute_model(cls, analysis_model, *args, **kwargs): "crystal3dAnimation", "tempProfileAnimation", "tempHeatMapAnimation", - "plotAnimation", - "plot2Animation", ): return "crystalAnimation" if "beamlineAnimation" in analysis_model: diff --git a/sirepo/template/silas.py b/sirepo/template/silas.py index e6482bd8a8..2678863ebb 100644 --- a/sirepo/template/silas.py +++ b/sirepo/template/silas.py @@ -19,7 +19,6 @@ _SIM_DATA, SIM_TYPE, SCHEMA = sirepo.sim_data.template_globals() -_CRYSTAL_CSV_FILE = "crystal.csv" _TEMP_PROFILE_FILE = "tempProfile.h5" _TEMP_HEATMAP_FILE = "tempHeatMap.h5" _RESULTS_FILE = "results{}.h5" @@ -309,38 +308,6 @@ def _crystal_animation_percent_complete(run_dir, res, data): return res -def _crystal_plot(frame_args): - x = None - plots = [] - with open(str(frame_args.run_dir.join(_CRYSTAL_CSV_FILE))) as f: - for r in csv.reader(f): - if x is None and r[0] == x_column: - r.pop(0) - r.pop(0) - x = [float(v) * scale for v in r] - elif r[0] == y_column: - r.pop(0) - t = r.pop(0) - plots.append( - PKDict( - points=[float(v) for v in r], - label="{:.1f} sec".format(float(t)), - ) - ) - return PKDict( - title="", - x_range=[min(x), max(x)], - y_label="Temperature [°C]", - x_label=x_heading, - x_points=x, - plots=plots, - y_range=template_common.compute_plot_color_and_range(plots), - summaryData=PKDict( - crystalLength=_get_crystal(frame_args.sim_in).length, - ), - ) - - def _generate_beamline_elements(data): def _callback(state, element, dz): if dz: @@ -425,7 +392,7 @@ def _generate_parameters_file(data): res, v = template_common.generate_parameters_file(data) if data.report == "crystalAnimation": - c = _get_crystal(data) + c = data.models.thermalTransportCrystal.crystal if c.pump_rep_rate <= 1: c.calc_type = "fenics" v.crystalParams = PKDict( @@ -445,7 +412,6 @@ def _generate_parameters_file(data): ) v.pump_pulse_profile = c.pump_pulse_profile v.crystalLength = c.length - v.crystalCSV = _CRYSTAL_CSV_FILE v.thermalCrystal = c return res + template_common.render_jinja(SIM_TYPE, v, "crystal.py") if data.report in _SIM_DATA.SOURCE_REPORTS: @@ -461,10 +427,6 @@ def _generate_parameters_file(data): return res + template_common.render_jinja(SIM_TYPE, v) -def _get_crystal(data): - return data.models.thermalTransportCrystal.crystal - - def _initial_intensity_percent_complete(run_dir, res, data, model_names): res.outputInfo = [] if run_dir.join(_RESULTS_FILE.format(0)).exists(): @@ -614,25 +576,6 @@ def gen(self): raise AssertionError("Report is unavailable") -def _laser_pulse_report(value_index, filename, title, label): - values = numpy.load(filename) - return template_common.parameter_plot( - values[0].tolist(), - [ - PKDict( - points=values[value_index].tolist(), - label=label, - ), - ], - PKDict(), - PKDict( - title=title, - y_label="", - x_label="s [m]", - ), - ) - - def _parse_silas_log(run_dir): res = "" path = run_dir.join(template_common.RUN_LOG)