Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #6022 srw scale wavefront during sim #6186

Merged
merged 96 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
4608fe3
#6022 - ckp
Jul 18, 2023
2634cf8
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Jul 20, 2023
0d88775
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Jul 21, 2023
fa7af93
#6022 - preprocessing structure
Jul 21, 2023
1f4d863
#6022 - ckp
Jul 22, 2023
6ee3fc8
#6022 - sync with master
Jul 24, 2023
12e9d08
#6022 - ckp
Jul 25, 2023
2959106
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Jul 25, 2023
b97559f
#6022 - ckp
Jul 25, 2023
2160fbd
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Jul 26, 2023
173932b
#6022 - revert wavefront handling
Jul 26, 2023
c8a9ce7
#6022 - ckp
Jul 27, 2023
49279fb
#6022 - ckp
Jul 27, 2023
e1987eb
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Jul 27, 2023
ec2f400
#6022 - refactoring
Jul 27, 2023
e50570c
#6022 - process final watchpoints
Jul 27, 2023
c97187f
#6022 - ckp
Jul 27, 2023
1f4372c
#6022 - ckp
Jul 28, 2023
ad96323
#6022 - report resize and rotate to jinja
Jul 28, 2023
fe69aec
#6022 - count intensities instead of wavefronts
Jul 28, 2023
974e9c6
#6022 - ckp
Jul 31, 2023
0e3add6
#6022 - use inspect to copy scaling fns to jinja
Jul 31, 2023
5e44915
#6022 - import numpy in resizing fns
Jul 31, 2023
b3de3f5
#6022 - import pkdc in resizing fns
Jul 31, 2023
1f3da7b
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Jul 31, 2023
136b347
#6022 - ckp
Jul 31, 2023
d35e21f
#6022 - skip resize for beamlineAnimation
Jul 31, 2023
01ad5a3
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 1, 2023
648eba6
#6022 - retry beamline animation reads
Aug 1, 2023
942b78e
#6022 - cleanup
Aug 1, 2023
24f4dcb
#6022 - cleanup
Aug 1, 2023
a378bd4
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 1, 2023
1da7d60
#6022 - move pickle import
Aug 1, 2023
c99ea42
#6022 - move numpy import
Aug 1, 2023
638733f
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 1, 2023
68ffca6
#6022 - no wp scaling if not beamlineAnimation
Aug 1, 2023
64eded4
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 7, 2023
a0ec919
#6022 - moving to run_epilogue
Aug 7, 2023
e64a6cc
#6022 - ckp
Aug 7, 2023
1c2e771
#6022 - ckp
Aug 7, 2023
520aa3d
#6022 - ckp
Aug 7, 2023
c8743fe
#6022 - process watchpoints
Aug 7, 2023
7b1c0e0
#6022 - added run_on_server
Aug 7, 2023
187074b
#6022 - fm
Aug 7, 2023
ab1199e
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 7, 2023
05b0219
#6022 - save tmp intensity file and rename
Aug 8, 2023
85a5574
Merge branch '6022-srw-scale-wavefront-during-sim' of https://github.…
Aug 8, 2023
d914ebf
#6022 - refactor
Aug 8, 2023
24665dd
#6022 - fmt
Aug 8, 2023
3cdff4e
#6022 - use srwpy
Aug 8, 2023
0ed6432
#6022 - revert to import srwl_bl for tests
Aug 8, 2023
ea2863e
#6022 - fix for 0-1 watchpoints
Aug 9, 2023
82c90ac
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 9, 2023
5e2a07d
#6022 - removed redundant imports
Aug 9, 2023
eedae25
#6022 - cleanup
Aug 9, 2023
e4ab070
#6022 - removed run_on_server
Aug 9, 2023
2709c4b
#6022 - cleaned up jinja
Aug 9, 2023
5e8e848
#6022 - cleaned up jinja
Aug 9, 2023
25d3a7f
#6022 - cleanup
Aug 9, 2023
8d1a37c
#6022 - fmt
Aug 9, 2023
7501dd2
#6022 - creating test
Aug 10, 2023
0039fa2
#6022 - added test_srw_resize_3d
Aug 10, 2023
7cf62e8
#6022 - fmt
Aug 10, 2023
05493a0
#6022 - separated nx and ny tests
Aug 10, 2023
851a07b
#6022 - using pkconfig.reset_state_for_testing
Aug 10, 2023
d695f0d
#6022 - moved reset_state_for_testing
Aug 10, 2023
9dac7fe
#6022 - fmt
Aug 10, 2023
d67e788
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 10, 2023
5b78a15
#6022 - removed import pytest
Aug 11, 2023
57df580
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 15, 2023
b0f1645
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 25, 2023
d9155e1
#6022 - ckp
Aug 26, 2023
c9edc00
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 29, 2023
3f9a4dc
#6022 - cleanup
Aug 29, 2023
b46edd5
#6022 - ckp
Aug 29, 2023
1dd3f76
#6022 - count wavefront files
Aug 30, 2023
4864724
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
Aug 30, 2023
7c0b7c0
#6022 - process next to last properly
Aug 30, 2023
91e1dab
#6022 - call ResizeElecFieldMesh
Aug 30, 2023
4b49daf
#6022 - fmt
Aug 30, 2023
e2591ee
#6022 - ignore plot params when sizing wfr
Aug 30, 2023
b18d186
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 30, 2023
6a26578
#6022 - cleanup
Aug 30, 2023
9229dc5
Merge branch '6022-srw-scale-wavefront-during-sim' of https://github.…
Aug 30, 2023
9b1fc96
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 30, 2023
9f0e99e
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Aug 31, 2023
ab43700
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Sep 12, 2023
d0d528f
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Sep 13, 2023
1c2841f
for #6022 rework maximum report dimension calculations
moellep Sep 16, 2023
e9e7a83
fpc
moellep Sep 16, 2023
3989e98
removed unused imports
moellep Sep 16, 2023
b82439c
update test
moellep Sep 16, 2023
207b1e4
removed unused method
moellep Sep 18, 2023
7e2b51e
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
moellep Sep 18, 2023
032066b
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Sep 18, 2023
fa43d46
Merge branch 'master' into 6022-srw-scale-wavefront-during-sim
mkeilman Sep 18, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion sirepo/package_data/template/srw/parameters.py.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ try:
except:
pass

{% if in_server %}
import sirepo.template
{% endif %}
import srwl_bl
import srwlib
import srwlpy
Expand Down Expand Up @@ -431,7 +434,6 @@ def _rsopt_set_params({{ rsOptFuctionSignature() }}):

def epilogue():
{% if in_server %}
import sirepo.template
sirepo.template.run_epilogue('srw')
{% else %}
pass
Expand Down
142 changes: 100 additions & 42 deletions sirepo/template/srw.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from sirepo import simulation_db
from sirepo.template import srw_common
from sirepo.template import template_common
import srwl_bl
import array
import copy
import math
Expand All @@ -23,7 +24,6 @@
import sirepo.mpi
import sirepo.sim_data
import sirepo.util
import srwl_bl
import srwlib
import time
import traceback
Expand Down Expand Up @@ -145,6 +145,8 @@

_JSON_MESSAGE_EXPANSION = 20

_MAX_MESSAGE_BYTES = sirepo.job.cfg().max_message_bytes
mkeilman marked this conversation as resolved.
Show resolved Hide resolved

_RSOPT_PARAMS = {
i
for sublist in [
Expand Down Expand Up @@ -438,6 +440,7 @@ def extract_report_data(sim_in):
),
)
if out.dimensions == 3:
res.report = r
res = _remap_3d(res, allrange, out, dm[r])
return res

Expand Down Expand Up @@ -501,28 +504,14 @@ def sim_frame(frame_args):
_copy_frame_args_into_model(frame_args, r)
elif "beamlineAnimation" in r:
wid = int(re.search(r".*?(\d+)$", r)[1])
fn = _wavefront_pickle_filename(wid)
with open(fn, "rb") as f:
wfr = pickle.load(f)
m = _copy_frame_args_into_model(frame_args, "watchpointReport")
if wid:
m.id = wid
frame_args.sim_in.report = "beamlineAnimation"
frame_args.sim_in.models.beamlineAnimation = m
data_file = _OUTPUT_FOR_MODEL.beamlineAnimation.filename.format(
watchpoint_id=wid
)
else:
frame_args.sim_in.report = "initialIntensityReport"
frame_args.sim_in.models.initialIntensityReport = m
data_file = _OUTPUT_FOR_MODEL.initialIntensityReport.filename
srwl_bl.SRWLBeamline().calc_int_from_wfr(
wfr,
_pol=int(frame_args.polarization),
_int_type=int(frame_args.characteristic),
_fname=data_file,
_pr=False,
)
if "beamlineAnimation" not in r:
# some reports may be written at the same time as the reader
# if the file is invalid, wait a bit and try again
Expand Down Expand Up @@ -787,6 +776,50 @@ def process_undulator_definition(model):
return model


def process_watch(wid=0):
def _op():
sim_in = simulation_db.read_json(template_common.INPUT_BASE_NAME)
report = sim_in.models[f"beamlineAnimation{wid}"]
with open(_wavefront_pickle_filename(wid), "rb") as f:
wfr = pickle.load(f)
data, mesh = srwl_bl.SRWLBeamline().calc_int_from_wfr(
wfr,
_pol=int(report.get("polarization", "6")),
_int_type=int(report.get("characteristic", "0")),
_pr=False,
)
d, x_range, y_range = _reshape_3d(
np.array(data),
[0, 0, 0, mesh.xStart, mesh.xFin, mesh.nx, mesh.yStart, mesh.yFin, mesh.ny],
report,
)
new_mesh = srwlib.SRWLRadMesh(
_eStart=mesh.eStart,
_eFin=mesh.eFin,
_ne=mesh.ne,
_xStart=x_range[0],
_xFin=x_range[1],
_nx=x_range[2],
_yStart=y_range[0],
_yFin=y_range[1],
_ny=y_range[2],
_zStart=mesh.zStart,
_nvx=mesh.nvx,
_nvy=mesh.nvy,
_nvz=mesh.nvz,
_hvx=mesh.hvx,
_hvy=mesh.hvy,
_hvz=mesh.hvz,
_arSurf=mesh.arSurf,
)
dst = _wavefront_intensity_filename(wid)
src = f"tmp_{dst}"
srwlib.srwl_uti_save_intens_ascii(d.flatten().tolist(), new_mesh, src)
pkio.py_path(src).rename(dst)

sirepo.mpi.restrict_op_to_first_rank(_op)


def python_source_for_model(data, model, qcall, plot_reports=True, **kwargs):
data.report = model or _SIM_DATA.SRW_RUN_ALL_MODEL
data.report = re.sub("beamlineAnimation0", "initialIntensityReport", data.report)
Expand Down Expand Up @@ -1143,7 +1176,7 @@ def _beamline_animation_percent_complete(run_dir, res):
res.outputInfo = [
PKDict(
modelKey="beamlineAnimation0",
filename=_wavefront_pickle_filename(0),
filename=_wavefront_intensity_filename(0),
id=0,
),
]
Expand All @@ -1156,16 +1189,14 @@ def _beamline_animation_percent_complete(run_dir, res):
PKDict(
waitForData=True,
modelKey=f"beamlineAnimation{item.id}",
filename=_wavefront_pickle_filename(item.id),
filename=_wavefront_intensity_filename(item.id),
id=item.id,
)
)
count = 0
for info in res.outputInfo:
try:
with open(info.filename, "rb") as f:
# TODO(pjm): instead look at last byte == pickle.STOP, see template_common.read_last_csv_line()
wfr = pickle.load(f)
if template_common.read_last_csv_line(pkio.py_path(info.filename)):
count += 1
info.waitForData = False
except Exception as e:
Expand Down Expand Up @@ -1956,6 +1987,7 @@ def _generate_srw_main(data, plot_reports, beamline_info):
source_type = data.models.simulation.sourceType
run_all = report == _SIM_DATA.SRW_RUN_ALL_MODEL or is_for_rsopt
vp_var = "vp" if is_for_rsopt else "varParam"
final_watch = None
content = [
f"v = srwl_bl.srwl_uti_parse_options(srwl_bl.srwl_uti_ext_options({vp_var}), use_sys_argv={plot_reports})",
]
Expand All @@ -1975,10 +2007,12 @@ def _generate_srw_main(data, plot_reports, beamline_info):
content.append("op = None")
content.append("v.ws_fne = '{}'".format(_wavefront_pickle_filename(0)))
prev_wavefront = None
prev_watch = 0
names = []
for n in beamline_info.names:
names.append(n)
if n in beamline_info.watches:
final_watch = n
is_last_watch = n == beamline_info.names[-1]
content.append("names = ['" + "','".join(names) + "']")
names = []
Expand All @@ -1989,6 +2023,11 @@ def _generate_srw_main(data, plot_reports, beamline_info):
content.append("op = set_optics(v, names, {})".format(is_last_watch))
if not is_last_watch:
content.append("srwl_bl.SRWLBeamline(_name=v.name).calc_all(v, op)")
content.append(
f"sirepo.template.import_module('srw').process_watch(wid={prev_watch})"
)
prev_watch = beamline_info.watches[n]

elif run_all or (
_SIM_DATA.srw_is_beamline_report(report) and len(data.models.beamline)
):
Expand Down Expand Up @@ -2057,6 +2096,10 @@ def _generate_srw_main(data, plot_reports, beamline_info):
if plot_reports:
content.append("v.tr_pl = 'xz'")
content.append("srwl_bl.SRWLBeamline(_name=v.name).calc_all(v, op)")
if report == "beamlineAnimation":
content.append(
f"sirepo.template.import_module('srw').process_watch(wid={beamline_info.watches.get(final_watch, 0)})"
)
return "\n".join(
[f" {x}" for x in content] + [""] + ([] if is_for_rsopt else ["main()", ""])
)
Expand Down Expand Up @@ -2162,21 +2205,10 @@ def _process_rsopt_elements(els):


def _remap_3d(info, allrange, out, report):
x_range = [allrange[3], allrange[4], allrange[5]]
y_range = [allrange[6], allrange[7], allrange[8]]
ar2d = info.points
totLen = int(x_range[2] * y_range[2])
n = len(ar2d) if totLen > len(ar2d) else totLen
ar2d = np.reshape(ar2d[0:n], (int(y_range[2]), int(x_range[2])))

if report.get("usePlotRange", "0") == "1":
ar2d, x_range, y_range = _update_report_range(report, ar2d, x_range, y_range)
if report.get("useIntensityLimits", "0") == "1":
ar2d[ar2d < report.minIntensityLimit] = report.minIntensityLimit
ar2d[ar2d > report.maxIntensityLimit] = report.maxIntensityLimit
ar2d, x_range, y_range = _resize_report(report, ar2d, x_range, y_range)
if report.get("rotateAngle", 0):
ar2d, x_range, y_range = _rotate_report(report, ar2d, x_range, y_range, info)
ar2d, x_range, y_range = _reshape_3d(np.array(info.points), allrange, report)
rotate_angle = report.get("rotateAngle", 0)
if rotate_angle and info.title != "Power Density":
info.subtitle = info.subtitle + " Image Rotate {}^0".format(rotate_angle)
if out.units[2]:
out.labels[2] = "{} [{}]".format(out.labels[2], out.units[2])
if report.get("useIntensityLimits", "0") == "1":
Expand All @@ -2197,16 +2229,33 @@ def _remap_3d(info, allrange, out, report):
)


def _reshape_3d(ar1d, allrange, report):
x_range = [allrange[3], allrange[4], allrange[5]]
y_range = [allrange[6], allrange[7], allrange[8]]
totLen = int(x_range[2] * y_range[2])
n = len(ar1d) if totLen > len(ar1d) else totLen
ar2d = np.reshape(ar1d[0:n], (int(y_range[2]), int(x_range[2])))
if report.get("usePlotRange", "0") == "1":
ar2d, x_range, y_range = _update_report_range(report, ar2d, x_range, y_range)
if report.get("useIntensityLimits", "0") == "1":
ar2d[ar2d < report["minIntensityLimit"]] = report["minIntensityLimit"]
ar2d[ar2d > report["maxIntensityLimit"]] = report["maxIntensityLimit"]
ar2d, x_range, y_range = _resize_report(report, ar2d, x_range, y_range)
if report.get("rotateAngle", 0):
ar2d, x_range, y_range = _rotate_report(report, ar2d, x_range, y_range)
return ar2d, x_range, y_range


def _resize_report(report, ar2d, x_range, y_range):
from pykern.pkdebug import pkdc

width_pixels = int(report.get("intensityPlotsWidth", 0))
if not width_pixels:
# upper limit is browser's max html canvas size
width_pixels = _CANVAS_MAX_SIZE
# roughly 20x size increase for json
if ar2d.size * _JSON_MESSAGE_EXPANSION > sirepo.job.cfg().max_message_bytes:
max_width = int(
math.sqrt(sirepo.job.cfg().max_message_bytes / _JSON_MESSAGE_EXPANSION)
)
if ar2d.size * _JSON_MESSAGE_EXPANSION > _MAX_MESSAGE_BYTES:
max_width = int(math.sqrt(_MAX_MESSAGE_BYTES / _JSON_MESSAGE_EXPANSION))
if max_width < width_pixels:
pkdc(
"auto scaling dimensions to fit message size. size: {}, max_width: {}",
Expand Down Expand Up @@ -2238,8 +2287,9 @@ def _resize_report(report, ar2d, x_range, y_range):
return ar2d, x_range, y_range


def _rotate_report(report, ar2d, x_range, y_range, info):
def _rotate_report(report, ar2d, x_range, y_range):
from scipy import ndimage
from pykern.pkdebug import pkdc

rotate_angle = report.rotateAngle
rotate_reshape = report.get("rotateReshape", "0") == "1"
Expand Down Expand Up @@ -2272,8 +2322,8 @@ def _rotate_report(report, ar2d, x_range, y_range, info):

x_range[2] = ar2d.shape[1]
y_range[2] = ar2d.shape[0]
if info.title != "Power Density":
info.subtitle = info.subtitle + " Image Rotate {}^0".format(rotate_angle)
# if info.title != "Power Density":
# info.subtitle = info.subtitle + " Image Rotate {}^0".format(rotate_angle)
return ar2d, x_range, y_range


Expand Down Expand Up @@ -2642,6 +2692,14 @@ def file_attrs_ok(attrs):
)


def _wavefront_intensity_filename(el_id):
return (
_OUTPUT_FOR_MODEL.beamlineAnimation.filename.format(watchpoint_id=el_id)
if el_id
else _OUTPUT_FOR_MODEL.initialIntensityReport.filename
)


def _wavefront_pickle_filename(el_id):
if el_id:
return f"wid-{el_id}.pkl"
Expand Down
36 changes: 36 additions & 0 deletions tests/template/srw_resize_3d_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
"""PyTest for :mod:`sirepo.template.srw`

:copyright: Copyright (c) 2023 RadiaSoft LLC. All Rights Reserved.
:license: http://www.apache.org/licenses/LICENSE-2.0.html
"""
from pykern.pkcollections import PKDict
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove these imports and add an import pytest

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see import pytest all over but it is rarely used. Also I still have to do the original imports in the test function. What does pytest do?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The import pytest brings in pytest (the testing framework) as the first thing in the program. It may be superstition at this point, but it used to do goofy things with "fixtures" when you didn't import pytest. Perhaps we can dispense with it. Let's try for this test.

from pykern.pkunit import pkeq, pkok

_N_BINS = 100


def setup_module(module):
import os

# Set max to something reasonable for testing
os.environ.update(
SIREPO_JOB_MAX_MESSAGE_BYTES=str(_N_BINS * _N_BINS),
)


def test_srw_resize_3d(fc):
mkeilman marked this conversation as resolved.
Show resolved Hide resolved
from sirepo.template import srw
import numpy

a, xr, yr = srw._reshape_3d(
mkeilman marked this conversation as resolved.
Show resolved Hide resolved
numpy.random.rand(srw._MAX_MESSAGE_BYTES),
mkeilman marked this conversation as resolved.
Show resolved Hide resolved
[0, 0, 0, 0.0, 1.0, _N_BINS, 0.0, 1.0, _N_BINS],
PKDict(),
)
pkok(
mkeilman marked this conversation as resolved.
Show resolved Hide resolved
xr[2] < _N_BINS and yr[2] < _N_BINS,
"did not reduce bins nx={} ny={}",
xr[2],
yr[2],
)