Skip to content

Commit a193a5c

Browse files
authored
Merge pull request #39 from ChristopherMayes/rework_output
Rework output
2 parents af7c776 + 3260c3b commit a193a5c

File tree

7 files changed

+660
-304
lines changed

7 files changed

+660
-304
lines changed

docs/examples/tutorial.ipynb

Lines changed: 359 additions & 46 deletions
Large diffs are not rendered by default.

environment.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
# conda env create -f environment-dev.yml
2-
name: pyemittance-dev
1+
# conda env create -f environment.yml
2+
name: pyemittance
33
channels:
44
- conda-forge
55
dependencies:

pyemittance/__init__.py

Lines changed: 1 addition & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,182 +1,5 @@
11
from . import _version
22
__version__ = _version.get_versions()['version']
33

4-
from pyemittance.observer import Observer
5-
from pyemittance.data_handler import adapt_range, check_symmetry, find_inflection_pnt, add_measurements_btwn_pnts
6-
from pyemittance.emittance_calc import EmitCalc
7-
from pyemittance.load_json_configs import load_configs
8-
9-
10-
class PyEmittance:
11-
12-
def __init__(self,
13-
config_name='LCLS_OTR2',
14-
config_dict=None, # supersedes json configs
15-
meas_type='OTRS',
16-
use_model=False,
17-
online=False
18-
):
19-
20-
# if config is not provided, use LCLS-OTR2 as default
21-
self.config_name = config_name
22-
self.config_dict = config_dict if config_dict else load_configs(self.config_name)
23-
24-
self.meas_type = meas_type
25-
# if running on machine, use_model=False
26-
self.use_model = use_model
27-
# only True if setting PVs
28-
self.online = online
29-
self.verbose = True
30-
31-
# injector settings (SOL, CQ, SQ) if optimizing
32-
self.inj_config = None
33-
# initial rough quad scan
34-
self.quad_init = [-6, -4, -2, 0]
35-
36-
# pyemittance method options
37-
self.adapt_ranges = True
38-
self.num_points = 7
39-
self.check_sym = True
40-
self.infl_check = True
41-
self.add_pnts = True
42-
self.show_plots = True
43-
self.use_prev_meas = True
44-
self.quad_tol = 0.05
45-
self.save_runs = False
46-
self.calc_bmag = False
47-
48-
# simulation/model options
49-
# beamsize function from model
50-
self.get_bs_model = None
51-
self.add_noise = False
52-
53-
# to save total number of points queried
54-
self.return_num_points = False
55-
56-
def measure_emittance(self):
57-
# get initial points from the observer
58-
o = Observer([], {'x': [], 'y': []}, {'x': [], 'y': []})
59-
o.use_model = self.use_model
60-
o.inj_config = self.inj_config
61-
o.online = self.online
62-
o.meas_type = self.meas_type
63-
o.use_prev_meas = self.use_prev_meas
64-
o.tolerance = self.quad_tol
65-
66-
# print warning
67-
if self.online and self.verbose:
68-
print("Running online!")
69-
else:
70-
print("Running offline.")
71-
72-
# if using sim
73-
# set beamsize fn
74-
o.get_beamsizes_model = self.get_bs_model
75-
o.add_noise = self.add_noise
76-
77-
o.config_name = self.config_name
78-
o.config_dict = self.config_dict
79-
80-
energy = o.config_dict['beamline_info']['energy']
81-
l_quad = o.config_dict['beamline_info']['l']
82-
83-
# get initial beamsizes (rough scan)
84-
bs_x_list, bs_y_list, bs_x_list_err, bs_y_list_err = o.measure_beam(self.quad_init)
85-
86-
quad_range_x = self.quad_init
87-
quad_range_y = self.quad_init
88-
89-
if self.adapt_ranges:
90-
quad_range_x = adapt_range(quad_range_x,
91-
bs_x_list,
92-
'x',
93-
w=bs_x_list_err,
94-
energy=energy,
95-
l_eff=l_quad,
96-
num_points=self.num_points
97-
)
98-
quad_range_y = adapt_range(quad_range_y,
99-
bs_y_list,
100-
'y',
101-
w=bs_y_list_err,
102-
energy=energy,
103-
l_eff=l_quad,
104-
num_points=self.num_points
105-
)
106-
107-
new_beamsize_x = o.measure_beam(quad_range_x)
108-
bs_x_list, bs_x_list_err = new_beamsize_x[0], new_beamsize_x[2]
109-
new_beamsize_y = o.measure_beam(quad_range_y)
110-
bs_y_list, bs_y_list_err = new_beamsize_y[1], new_beamsize_y[3]
111-
112-
if self.check_sym:
113-
add_points_x = check_symmetry(quad_range_x, bs_x_list, bs_x_list_err, 'x',
114-
bs_fn=o.measure_beam, add_meas=True)
115-
add_points_y = check_symmetry(quad_range_y, bs_y_list, bs_y_list_err, 'y',
116-
bs_fn=o.measure_beam, add_meas=True)
117-
118-
if add_points_x is not None:
119-
quad_range_x = add_points_x[0]
120-
bs_x_list = add_points_x[1]
121-
bs_x_list_err = add_points_x[2]
122-
123-
if add_points_y is not None:
124-
quad_range_y = add_points_y[0]
125-
bs_y_list = add_points_y[1]
126-
bs_y_list_err = add_points_y[2]
127-
128-
if self.infl_check:
129-
left_x, right_x = find_inflection_pnt(quad_range_x,
130-
bs_x_list,
131-
show_plots=self.show_plots
132-
)
133-
left_y, right_y = find_inflection_pnt(quad_range_y,
134-
bs_y_list,
135-
show_plots=self.show_plots
136-
)
137-
138-
# truncate data
139-
quad_range_x = quad_range_x[left_x:right_x]
140-
bs_x_list = bs_x_list[left_x:right_x]
141-
bs_x_list_err = bs_x_list_err[left_x:right_x]
142-
143-
quad_range_y = quad_range_y[left_y:right_y]
144-
bs_y_list = bs_y_list[left_y:right_y]
145-
bs_y_list_err = bs_y_list_err[left_y:right_y]
146-
147-
if self.add_pnts:
148-
quad_range_x, bs_x_list, bs_x_list_err = add_measurements_btwn_pnts(quad_range_x,
149-
bs_x_list,
150-
bs_x_list_err,
151-
self.num_points,
152-
'x',
153-
bs_fn=o.measure_beam
154-
)
155-
quad_range_y, bs_y_list, bs_y_list_err = add_measurements_btwn_pnts(quad_range_y,
156-
bs_y_list,
157-
bs_y_list_err,
158-
self.num_points,
159-
'y',
160-
bs_fn=o.measure_beam
161-
)
162-
163-
# finally get emittance
164-
ef = EmitCalc({'x': quad_range_x, 'y': quad_range_y},
165-
{'x': bs_x_list, 'y': bs_y_list},
166-
{'x': bs_x_list_err, 'y': bs_y_list_err},
167-
config_dict=o.config_dict,
168-
config_name=o.config_name
169-
)
170-
ef.plot = self.show_plots
171-
ef.save_runs = self.save_runs
172-
ef.calc_bmag = self.calc_bmag
173-
174-
# get normalized transverse emittance
175-
ef.get_emit()
176-
177-
# save total number of points queried
178-
if self.return_num_points:
179-
ef.out_dict["total_points_measured"] = len(o.quad_meas)
180-
181-
return ef.out_dict
4+
from pyemittance.pyemittance import PyEmittance
1825

pyemittance/emit_eval_example.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,9 @@ def eval_emit_machine(inj_config=None,
108108
ef.get_emit()
109109

110110
# save total number of points queried
111-
ef.out_dict["total_points_measured"] = len(o.quad_meas)
111+
ef.output["total_points_measured"] = len(o.quad_meas)
112112

113-
return ef.out_dict
113+
return ef.output
114114

115115

116116
def eval_emit_surrogate(get_bs_model,
@@ -214,6 +214,6 @@ def eval_emit_surrogate(get_bs_model,
214214
ef.get_emit()
215215

216216
# save total number of points queried
217-
ef.out_dict["total_points_measured"] = len(o.quad_meas)
217+
ef.output["total_points_measured"] = len(o.quad_meas)
218218

219-
return ef.out_dict
219+
return ef.output

pyemittance/emittance_calc.py

Lines changed: 52 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -57,22 +57,7 @@ def __init__(self,
5757
self.init_saving()
5858

5959
# Main output of emittance calc
60-
self.out_dict = {'nemitx': None,
61-
'nemity': None,
62-
'nemitx_err': None,
63-
'nemity_err': None,
64-
'nemit': None,
65-
'nemit_err': None,
66-
'bmagx': None,
67-
'bmagy': None,
68-
'bmagx_err': None,
69-
'bmagy_err': None,
70-
'bmag_emit': None,
71-
'bmag_emit_err': None,
72-
'opt_q_x': None,
73-
'opt_q_y': None,
74-
'total_points_measured': None
75-
}
60+
self.output = {}
7661

7762
def load_config(self):
7863
# if path exists, load from path
@@ -121,48 +106,55 @@ def get_emit(self):
121106

122107
weights = self.weighting_func(bs, bs_err) # 1/sigma
123108

124-
# Storing quadvals and beamsizes in self.out_dict for plotting purposes
125-
self.out_dict[f'quadvals{dim}'] = list(q)
126-
self.out_dict[f'beamsizes{dim}'] = list(bs)
127-
self.out_dict[f'beamsizeserr{dim}'] = list(bs_err)
109+
# Storing quadvals and beamsizes in self.output for plotting purposes
110+
self.output[f'quadvals{dim}'] = list(q)
111+
self.output[f'beamsizes{dim}'] = list(bs)
112+
self.output[f'beamsizeserr{dim}'] = list(bs_err)
128113

129114
res = estimate_sigma_mat_thick_quad(bs, kL, bs_err, weights, dim=dim, Lquad=self.quad_len,
130-
energy=self.energy, rmat=self.rmat, calc_bmag=self.calc_bmag,
115+
energy=self.energy, rmat=self.rmat,
131116
plot=self.plot, verbose=self.verbose)
132-
if np.isnan(res[0]):
133-
self.out_dict['nemitx'], self.out_dict['nemity'] = np.nan, np.nan
134-
self.out_dict['nemitx_err'], self.out_dict['nemity_err'] = np.nan, np.nan
135-
self.out_dict['bmagx'], self.out_dict['bmagy'] = np.nan, np.nan
136-
self.out_dict['bmagx_err'], self.out_dict['bmagy_err'] = np.nan, np.nan
137-
return self.out_dict
138-
else:
139-
emit, emit_err, beta_rel_err, alpha_rel_err = res[0:4]
140-
if self.calc_bmag:
141-
sig_11, sig_12, sig_22 = res[4:]
142-
143-
norm_emit_res = normalize_emit(emit, emit_err, self.energy)
144-
self.out_dict[f'nemit{dim}'] = normalize_emit(emit, emit_err, self.energy)[0]
145-
self.out_dict[f'nemit{dim}_err'] = normalize_emit(emit, emit_err, self.energy)[1]
117+
# Add all results
118+
self.output.update(res)
119+
120+
# Skip further calcs if there was an error
121+
if res[f'error_{dim}']:
122+
continue
146123

147124
if self.calc_bmag:
148-
self.sig_mat_screen[dim] = [sig_11, sig_12, sig_22]
125+
if dim =='x':
126+
sig_11 = res['screen_sigma_11']
127+
sig_12 = res['screen_sigma_12']
128+
sig_22 = res['screen_sigma_22']
129+
130+
else:
131+
sig_11 = res['screen_sigma_33']
132+
sig_12 = res['screen_sigma_34']
133+
sig_22 = res['screen_sigma_44']
134+
self.sig_mat_screen[dim] = [sig_11, sig_12, sig_22]
135+
136+
beta_rel_err = res[f'beta_{dim}_rel_err']
137+
alpha_rel_err = res[f'alpha_{dim}_rel_err']
138+
139+
149140
self.beta_err = beta_rel_err
150141
self.alpha_err = alpha_rel_err
151142

152143
bmag_calc_res = self.get_twiss_bmag(dim=dim)
153144
# Get bmag and bmag_err
154-
self.out_dict[f'bmag{dim}'] = bmag_calc_res[0]
155-
self.out_dict[f'bmag{dim}_err'] = bmag_calc_res[1]
145+
self.output[f'screen_bmag{dim}'] = bmag_calc_res[0]
146+
self.output[f'screen_bmag{dim}_err'] = bmag_calc_res[1]
156147
# Get best value for scanning quad
157-
self.out_dict[f'opt_q_{dim}'] = q[bmag_calc_res[2]]
148+
self.output[f'optimal_quadval_{dim}'] = q[bmag_calc_res[2]]
158149

159-
# get geometric mean (set to None when x and y are not calculated)
160-
self.get_gmean_emit()
150+
# get geometric mean if possible
151+
if (not self.output['error_x']) and (not self.output['error_y']) :
152+
self.get_gmean_emit()
161153

162154
if self.save_runs:
163155
self.save_run()
164156

165-
return self.out_dict
157+
return self.output
166158

167159
def get_twiss_bmag(self, dim='x'):
168160

@@ -185,31 +177,31 @@ def get_twiss_bmag(self, dim='x'):
185177
def get_gmean_emit(self):
186178

187179
try:
188-
nemit = np.sqrt( self.out_dict['nemitx'] * self.out_dict['nemity'] )
189-
nemit_err = nemit * ( (self.out_dict['nemitx_err']/self.out_dict['nemitx'])**2 +
190-
(self.out_dict['nemity_err']/self.out_dict['nemity'])**2 )**0.5
180+
nemit = np.sqrt( self.output['norm_emit_x'] * self.output['norm_emit_y'] )
181+
nemit_err = nemit * ( (self.output['norm_emit_x_err']/self.output['norm_emit_x'])**2 +
182+
(self.output['norm_emit_y_err']/self.output['norm_emit_y'])**2 )**0.5
191183

192-
self.out_dict['nemit'] = nemit
193-
self.out_dict['nemit_err'] = nemit_err
184+
self.output['sqrt_norm_emit_4d'] = nemit
185+
self.output['sqrt_norm_emit_4d_err'] = nemit_err
194186

195-
if self.out_dict['bmagx'] is not None and self.out_dict['bmagy'] is not None:
196-
nbmag = np.sqrt( self.out_dict['bmagx'] * self.out_dict['bmagy'] )
187+
if 'bmag_x' in self.output and 'bmag_y' in self.output:
188+
nbmag = np.sqrt( self.output['bmag_x'] * self.output['bmag_y'] )
197189
bmag_emit_err = nemit*nbmag * (
198-
(self.out_dict['nemitx_err']/self.out_dict['nemitx'])**2 +
199-
(self.out_dict['nemity_err']/self.out_dict['nemity'])**2 +
200-
(self.out_dict['bmagx_err']/self.out_dict['bmagx'])**2 +
201-
(self.out_dict['bmagy_err']/self.out_dict['bmagy'])**2)**0.5
202-
self.out_dict['bmag_emit'] = nemit * nbmag
203-
self.out_dict['bmag_emit_err'] = bmag_emit_err
190+
(self.output['norm_emit_x_err']/self.output['norm_emit_x'])**2 +
191+
(self.output['norm_emit_y_err']/self.output['norm_emit_y'])**2 +
192+
(self.output['bmag_x_err']/self.output['bmag_x'])**2 +
193+
(self.output['bmag_y_err']/self.output['bmag_y'])**2)**0.5
194+
self.output['bmag_emit'] = nemit * nbmag
195+
self.output['bmag_emit_err'] = bmag_emit_err
204196

205197
except TypeError:
206-
self.out_dict['nemit'] = np.nan
207-
self.out_dict['nemit_err'] = np.nan
208-
self.out_dict['bmag_emit'] = np.nan
209-
self.out_dict['bmag_emit_err'] = np.nan
198+
self.output['sqrt_norm_emit_4d'] = np.nan
199+
self.output['sqrt_norm_emit_4d_err'] = np.nan
200+
self.output['bmag_emit'] = np.nan
201+
self.output['bmag_emit_err'] = np.nan
210202

211203
def save_run(self):
212-
save_emit_run(self.out_dict, path=self.config_dict['savepaths']['fits'])
204+
save_emit_run(self.output, path=self.config_dict['savepaths']['fits'])
213205

214206
def init_saving(self):
215207
"""Initialize dirs and files for saving"""

0 commit comments

Comments
 (0)