From cab97ab39394157b2593e9b8f0a82335c31ec303 Mon Sep 17 00:00:00 2001 From: Paul Moeller Date: Mon, 2 Sep 2024 19:41:36 +0000 Subject: [PATCH] for #7217 more dark mode improvements --- sirepo/package_data/static/css/lattice.css | 5 + .../package_data/static/css/sirepo-dark.css | 18 ++ sirepo/package_data/static/html/lattice.html | 4 +- sirepo/package_data/static/js/impactt.js | 7 +- .../static/json/impactt-schema.json | 2 +- sirepo/template/impactt.py | 163 ++++++++++-------- 6 files changed, 120 insertions(+), 79 deletions(-) diff --git a/sirepo/package_data/static/css/lattice.css b/sirepo/package_data/static/css/lattice.css index 58ce8873c5..bba2e8324c 100644 --- a/sirepo/package_data/static/css/lattice.css +++ b/sirepo/package_data/static/css/lattice.css @@ -145,3 +145,8 @@ div.sr-lattice-icon-disabled span { color: #333; border: 1px solid #777; } + +.sr-lattice-marker > path { + stroke: black; + stroke-width: 1; +} diff --git a/sirepo/package_data/static/css/sirepo-dark.css b/sirepo/package_data/static/css/sirepo-dark.css index ed24c4701b..94ff74cb34 100644 --- a/sirepo/package_data/static/css/sirepo-dark.css +++ b/sirepo/package_data/static/css/sirepo-dark.css @@ -12,6 +12,8 @@ --sr-panel-control-dark-mode: #21252a; --sr-panel-text-dark-mode: #eee; --sr-input-error-dark-mode: #430101; + --sr-table-border-dark-mode: #3d444db3; + --sr-body-color-dark-mode: #f0f6fc; } @media (prefers-color-scheme: dark) { :root { @@ -29,6 +31,7 @@ } body { + color: var(--sr-body-color-dark-mode); background-color: var(--sr-bg-dark-mode); } @@ -272,4 +275,19 @@ background-color: var(--sr-input-error-dark-mode); } + .table > tbody > tr > td { + border-top-color: var(--sr-table-border-dark-mode); + } + .table > thead > tr > th { + border-bottom-color: var(--sr-table-border-dark-mode); + color: var(--sr-panel-color); + } + .table > tbody > tr.active > td { + background-color: var(--sr-item-active-dark-mode); + color: var(--sr-bg-dark-mode); + } + + .sr-lattice-marker > path { + stroke: var(--sr-panel-text-dark-mode); + } } diff --git a/sirepo/package_data/static/html/lattice.html b/sirepo/package_data/static/html/lattice.html index 9aa840c332..874f3e3957 100644 --- a/sirepo/package_data/static/html/lattice.html +++ b/sirepo/package_data/static/html/lattice.html @@ -60,8 +60,8 @@ - - + + {{ markerUnits }} diff --git a/sirepo/package_data/static/js/impactt.js b/sirepo/package_data/static/js/impactt.js index 9779f423f4..fd5d1eca23 100644 --- a/sirepo/package_data/static/js/impactt.js +++ b/sirepo/package_data/static/js/impactt.js @@ -6,18 +6,13 @@ SIREPO.app.config(function() { SIREPO.appFieldEditors += ``; SIREPO.lattice = { elementColor: { - MULTIPOLE: 'yellow', - QUADRUPOLE: 'red', - DIPOLE: 'lightgreen', - SOLENOID: 'red', - DRIFT: 'grey', }, elementPic: { drift: ['DRIFT', 'EMFIELD_CARTESIAN', 'EMFIELD_CYLINDRICAL', 'WAKEFIELD'], lens: ['ROTATIONALLY_SYMMETRIC_TO_3D'], magnet: ['QUADRUPOLE', 'DIPOLE'], solenoid: ['SOLENOID', 'SOLRF'], - watch: ['WRITE_BEAM', 'WRITE_SLICE_INFO',], + watch: ['WRITE_BEAM', 'WRITE_SLICE_INFO'], zeroLength: [ 'CHANGE_TIMESTEP', 'OFFSET_BEAM', diff --git a/sirepo/package_data/static/json/impactt-schema.json b/sirepo/package_data/static/json/impactt-schema.json index a36c08575a..0904749cd0 100644 --- a/sirepo/package_data/static/json/impactt-schema.json +++ b/sirepo/package_data/static/json/impactt-schema.json @@ -218,7 +218,7 @@ "x": ["X Value", "PhaseSpaceCoordinate", "x"], "y": ["Y Value", "PhaseSpaceCoordinate", "px"], "plotType": ["Plot Type", "PlotType", "heatmap"], - "histogramBins": ["Histogram Bins", "Integer", 200], + "histogramBins": ["Histogram Bins", "Integer", 60], "colorMap": ["Color Map", "ColorMap", "viridis"], "aspectRatio": ["Aspect Ratio", "AspectRatio", "1"], "notes": ["Notes", "Text", ""], diff --git a/sirepo/template/impactt.py b/sirepo/template/impactt.py index f82ec3cbbc..323ce74026 100644 --- a/sirepo/template/impactt.py +++ b/sirepo/template/impactt.py @@ -79,17 +79,24 @@ def background_percent_complete(report, run_dir, is_running): ) -def bunch_plot(model, run_dir, frame_index, filename): - p = pmd_beamphysics.ParticleGroup(str(run_dir.join(filename))) +def bunch_plot(model, frame_index, particle_group): + def _label(name): + if name == "delta_z": + return "z -〈z〉" + if name == "energy": + return "E" + return name + return template_common.heatmap( - values=[p[model.x], p[model.y]], + values=[particle_group[model.x], particle_group[model.y]], model=model, plot_fields=PKDict( - x_label=f"{model.x} [{p.units(model.x)}]", - y_label=f"{model.y} [{p.units(model.y)}]", + x_label=f"{_label(model.x)} [{particle_group.units(model.x)}]", + y_label=f"{_label(model.y)} [{particle_group.units(model.y)}]", title=_PLOT_TITLE.get(f"{model.x}-{model.y}", f"{model.x} - {model.y}"), threshold=[1e-20, 1e20], ), + # weights=particle_group.weight, ) @@ -106,63 +113,14 @@ def sim_frame(frame_args): # elementAnimations return bunch_plot( frame_args, - frame_args.run_dir, frame_args.frameIndex, - _file_name_for_element_animation(frame_args), + pmd_beamphysics.ParticleGroup( + str(frame_args.run_dir.join(_file_name_for_element_animation(frame_args))) + ), ) -def load_many_fort(path, types=impact.parsers.FORT_STAT_TYPES, verbose=False): - """ - Loads a large dict with data from many fort files. - Checks that keys do not conflict. - - Default types are for typical statistical information along the simulation path. - - """ - fortfiles = impact.parsers.fort_files(path) - alldat = {} - size = None - for f in fortfiles: - file_type = impact.parsers.fort_type(f, verbose=False) - if file_type not in types: - continue - - dat = impact.parsers.load_fort(f, type=file_type, verbose=verbose) - for k in dat: - if isinstance(dat[k], dict): - alldat[k] = dat[k] - continue - if size is None: - size = len(dat[k]) - elif len(dat[k]) > size: - dat[k] = dat[k][:size] - if k not in alldat: - alldat[k] = dat[k] - - elif numpy.allclose(alldat[k], dat[k], atol=1e-20): - # If the difference between alldat-dat < 1e-20, - # move on to next key without error. - # https://numpy.org/devdocs/reference/generated/numpy.isclose.html#numpy.isclose - pass - - else: - # Data is not close enough to ignore differences. - # Check that this data is the same as what's already in there - assert numpy.all(alldat[k] == dat[k]), "Conflicting data for key:" + k - - return alldat - - -def sim_frame_statAnimation(frame_args): - # TODO(pjm): monkey patch to avoid shape errors when loading during updates - impact.parsers.load_many_fort = load_many_fort - I = impact.Impact( - use_temp_dir=False, - workdir=str(frame_args.run_dir), - ) - I.load_input(I._workdir + "/ImpactT.in") - I.load_output() +def stat_animation(I, frame_args): stats = I.output["stats"] plots = PKDict() if frame_args.x == "none": @@ -218,6 +176,18 @@ def sim_frame_statAnimation(frame_args): ) +def sim_frame_statAnimation(frame_args): + # TODO(pjm): monkey patch to avoid shape errors when loading during updates + impact.parsers.load_many_fort = _patched_load_many_fort + I = impact.Impact( + use_temp_dir=False, + workdir=str(frame_args.run_dir), + ) + I.load_input(I._workdir + "/ImpactT.in") + I.load_output() + return stat_animation(I, frame_args) + + def write_parameters(data, run_dir, is_parallel): pkio.write_text( run_dir.join(template_common.PARAMETERS_PYTHON_FILE), @@ -350,24 +320,77 @@ def _next_output_id(output_ids): return i -def _output_info(data, run_dir): +def output_info(data): res = [] for idx, n in enumerate(_output_names(data)): - fn = f"{n}.h5" - if run_dir.join(fn).exists(): - res.append( - PKDict( - modelKey=f"elementAnimation{idx}", - reportIndex=idx, - report="elementAnimation", - name=n, - filename=fn, - frameCount=1, - ) + res.append( + PKDict( + modelKey=f"elementAnimation{idx}", + reportIndex=idx, + report="elementAnimation", + name=n, + frameCount=1, ) + ) + return res + + +def _output_info(data, run_dir): + res = [] + for r in output_info(data): + fn = f"{r.name}.h5" + if run_dir.join(fn).exists(): + r.filename = fn + res.append(r) return res +# This method is copied, modified and monkey patched from the impact.parsers module. +# The method can be called while files are still being written, so the size is adjusted +# if later files have a longer length. +# +def _patched_load_many_fort(path, types=impact.parsers.FORT_STAT_TYPES, verbose=False): + """ + Loads a large dict with data from many fort files. + Checks that keys do not conflict. + + Default types are for typical statistical information along the simulation path. + + """ + fortfiles = impact.parsers.fort_files(path) + alldat = {} + size = None + for f in fortfiles: + file_type = impact.parsers.fort_type(f, verbose=False) + if file_type not in types: + continue + + dat = impact.parsers.load_fort(f, type=file_type, verbose=verbose) + for k in dat: + if isinstance(dat[k], dict): + alldat[k] = dat[k] + continue + if size is None: + size = len(dat[k]) + elif len(dat[k]) > size: + dat[k] = dat[k][:size] + if k not in alldat: + alldat[k] = dat[k] + + elif numpy.allclose(alldat[k], dat[k], atol=1e-20): + # If the difference between alldat-dat < 1e-20, + # move on to next key without error. + # https://numpy.org/devdocs/reference/generated/numpy.isclose.html#numpy.isclose + pass + + else: + # Data is not close enough to ignore differences. + # Check that this data is the same as what's already in there + assert numpy.all(alldat[k] == dat[k]), "Conflicting data for key:" + k + + return alldat + + def _plot_label(field): l = mathlabel(field) if re.search(r"mathrm|None", l):