|
1 | 1 | """Acceptance computation""" |
| 2 | + |
2 | 3 | import numpy |
3 | 4 | from .boundary import GridMode |
| 5 | + |
4 | 6 | # noinspection PyProtectedMember |
5 | 7 | from .boundary import boundary_search |
6 | 8 | from typing import Optional, Sequence |
7 | 9 | import multiprocessing |
8 | | -from ..lattice import Lattice, Refpts, frequency_control, AtError |
| 10 | +from ..lattice import Lattice, Refpts, frequency_control |
9 | 11 |
|
10 | 12 |
|
11 | | -__all__ = ['get_acceptance', 'get_1d_acceptance', 'get_horizontal_acceptance', |
12 | | - 'get_vertical_acceptance', 'get_momentum_acceptance'] |
| 13 | +__all__ = [ |
| 14 | + "get_acceptance", |
| 15 | + "get_1d_acceptance", |
| 16 | + "get_horizontal_acceptance", |
| 17 | + "get_vertical_acceptance", |
| 18 | + "get_momentum_acceptance", |
| 19 | +] |
13 | 20 |
|
14 | 21 |
|
15 | 22 | @frequency_control |
16 | 23 | def get_acceptance( |
17 | | - ring: Lattice, planes, npoints, amplitudes, |
18 | | - nturns: Optional[int] = 1024, |
19 | | - refpts: Optional[Refpts] = None, |
20 | | - dp: Optional[float] = None, |
21 | | - offset: Sequence[float] = None, bounds=None, |
22 | | - grid_mode: Optional[GridMode] = GridMode.RADIAL, |
23 | | - use_mp: Optional[bool] = False, |
24 | | - verbose: Optional[bool] = True, |
25 | | - divider: Optional[int] = 2, |
26 | | - shift_zero: Optional[float] = 1.0e-6, |
27 | | - start_method: Optional[str] = None, |
| 24 | + ring: Lattice, |
| 25 | + planes, |
| 26 | + npoints, |
| 27 | + amplitudes, |
| 28 | + nturns: Optional[int] = 1024, |
| 29 | + refpts: Optional[Refpts] = None, |
| 30 | + dp: Optional[float] = None, |
| 31 | + offset: Sequence[float] = None, |
| 32 | + bounds=None, |
| 33 | + grid_mode: Optional[GridMode] = GridMode.RADIAL, |
| 34 | + use_mp: Optional[bool] = False, |
| 35 | + verbose: Optional[bool] = True, |
| 36 | + divider: Optional[int] = 2, |
| 37 | + shift_zero: Optional[float] = 1.0e-6, |
| 38 | + start_method: Optional[str] = None, |
28 | 39 | ): |
29 | 40 | # noinspection PyUnresolvedReferences |
30 | 41 | r"""Computes the acceptance at ``repfts`` observation points |
@@ -91,92 +102,86 @@ def get_acceptance( |
91 | 102 | * When``use_mp=True`` all the available CPUs will be used. |
92 | 103 | This behavior can be changed by setting |
93 | 104 | ``at.DConstant.patpass_poolsize`` to the desired value |
| 105 | + * When multiple ``refpts`` are provided particles are first |
| 106 | + projected to the beginning of the ring with tracking. Then, |
| 107 | + all particles are tracked up to ``nturns``. This allows to |
| 108 | + do most of the work in a single function call and allows for |
| 109 | + full parallelization. |
94 | 110 | """ |
95 | 111 | kwargs = {} |
96 | 112 | if start_method is not None: |
97 | | - kwargs['start_method'] = start_method |
| 113 | + kwargs["start_method"] = start_method |
98 | 114 |
|
99 | 115 | if verbose: |
100 | 116 | nproc = multiprocessing.cpu_count() |
101 | | - print('\n{0} cpu found for acceptance calculation'.format(nproc)) |
| 117 | + print("\n{0} cpu found for acceptance calculation".format(nproc)) |
102 | 118 | if use_mp: |
103 | 119 | nprocu = nproc |
104 | | - print('Multi-process acceptance calculation selected...') |
| 120 | + print("Multi-process acceptance calculation selected...") |
105 | 121 | if nproc == 1: |
106 | | - print('Consider use_mp=False for single core computations') |
| 122 | + print("Consider use_mp=False for single core computations") |
107 | 123 | else: |
108 | 124 | nprocu = 1 |
109 | | - print('Single process acceptance calculation selected...') |
| 125 | + print("Single process acceptance calculation selected...") |
110 | 126 | if nproc > 1: |
111 | | - print('Consider use_mp=True for parallelized computations') |
| 127 | + print("Consider use_mp=True for parallelized computations") |
112 | 128 | np = numpy.atleast_1d(npoints) |
113 | 129 | na = 2 |
114 | 130 | if len(np) == 2: |
115 | 131 | na = np[1] |
116 | 132 | npp = numpy.prod(npoints) |
117 | | - rpp = 2*numpy.ceil(numpy.log2(np[0]))*numpy.ceil(na/nprocu) |
118 | | - mpp = npp/nprocu |
| 133 | + rpp = 2 * numpy.ceil(numpy.log2(np[0])) * numpy.ceil(na / nprocu) |
| 134 | + mpp = npp / nprocu |
119 | 135 | if rpp > mpp: |
120 | | - cond = (grid_mode is GridMode.RADIAL or |
121 | | - grid_mode is GridMode.CARTESIAN) |
| 136 | + cond = grid_mode is GridMode.RADIAL or grid_mode is GridMode.CARTESIAN |
122 | 137 | else: |
123 | 138 | cond = grid_mode is GridMode.RECURSIVE |
124 | 139 | if rpp > mpp and not cond: |
125 | | - print('The estimated load for grid mode is {0}'.format(mpp)) |
126 | | - print('The estimated load for recursive mode is {0}'.format(rpp)) |
127 | | - print('{0} or {1} is recommended'.format(GridMode.RADIAL, |
128 | | - GridMode.CARTESIAN)) |
| 140 | + print("The estimated load for grid mode is {0}".format(mpp)) |
| 141 | + print("The estimated load for recursive mode is {0}".format(rpp)) |
| 142 | + print( |
| 143 | + "{0} or {1} is recommended".format(GridMode.RADIAL, GridMode.CARTESIAN) |
| 144 | + ) |
129 | 145 | elif rpp < mpp and not cond: |
130 | | - print('The estimated load for grid mode is {0}'.format(mpp)) |
131 | | - print('The estimated load for recursive mode is {0}'.format(rpp)) |
132 | | - print('{0} is recommended'.format(GridMode.RECURSIVE)) |
133 | | - |
134 | | - boundary = [] |
135 | | - survived = [] |
136 | | - grid = [] |
137 | | - if refpts is not None: |
138 | | - rp = ring.uint32_refpts(refpts) |
139 | | - else: |
140 | | - rp = numpy.atleast_1d(refpts) |
141 | | - if offset is not None: |
142 | | - try: |
143 | | - offset = numpy.broadcast_to(offset, (len(rp), 6)) |
144 | | - except ValueError: |
145 | | - msg = ('offset and refpts have incoherent ' |
146 | | - 'shapes: {0}, {1}'.format(numpy.shape(offset), |
147 | | - numpy.shape(refpts))) |
148 | | - raise AtError(msg) |
149 | | - else: |
150 | | - offset=[None for _ in rp] |
151 | | - for r, o in zip(rp, offset): |
152 | | - b, s, g = boundary_search(ring, planes, npoints, amplitudes, |
153 | | - nturns=nturns, obspt=r, dp=dp, |
154 | | - offset=o, bounds=bounds, |
155 | | - grid_mode=grid_mode, use_mp=use_mp, |
156 | | - verbose=verbose, divider=divider, |
157 | | - shift_zero=shift_zero, **kwargs) |
158 | | - boundary.append(b) |
159 | | - survived.append(s) |
160 | | - grid.append(g) |
161 | | - if len(rp) == 1: |
162 | | - return boundary[0], survived[0], grid[0] |
163 | | - else: |
164 | | - return boundary, survived, grid |
| 146 | + print("The estimated load for grid mode is {0}".format(mpp)) |
| 147 | + print("The estimated load for recursive mode is {0}".format(rpp)) |
| 148 | + print("{0} is recommended".format(GridMode.RECURSIVE)) |
| 149 | + |
| 150 | + b, s, g = boundary_search( |
| 151 | + ring, |
| 152 | + planes, |
| 153 | + npoints, |
| 154 | + amplitudes, |
| 155 | + nturns=nturns, |
| 156 | + obspt=refpts, |
| 157 | + dp=dp, |
| 158 | + offset=offset, |
| 159 | + bounds=bounds, |
| 160 | + grid_mode=grid_mode, |
| 161 | + use_mp=use_mp, |
| 162 | + verbose=verbose, |
| 163 | + divider=divider, |
| 164 | + shift_zero=shift_zero, |
| 165 | + **kwargs, |
| 166 | + ) |
| 167 | + return b, s, g |
165 | 168 |
|
166 | 169 |
|
167 | 170 | def get_1d_acceptance( |
168 | | - ring: Lattice, plane: str, resolution: float, amplitude: float, |
169 | | - nturns: Optional[int] = 1024, |
170 | | - refpts: Optional[Refpts] = None, |
171 | | - dp: Optional[float] = None, |
172 | | - offset: Sequence[float] = None, |
173 | | - grid_mode: Optional[GridMode] = GridMode.RADIAL, |
174 | | - use_mp: Optional[bool] = False, |
175 | | - verbose: Optional[bool] = False, |
176 | | - divider: Optional[int] = 2, |
177 | | - shift_zero: Optional[float] = 1.0e-6, |
178 | | - start_method: Optional[str] = None, |
179 | | - |
| 171 | + ring: Lattice, |
| 172 | + plane: str, |
| 173 | + resolution: float, |
| 174 | + amplitude: float, |
| 175 | + nturns: Optional[int] = 1024, |
| 176 | + refpts: Optional[Refpts] = None, |
| 177 | + dp: Optional[float] = None, |
| 178 | + offset: Sequence[float] = None, |
| 179 | + grid_mode: Optional[GridMode] = GridMode.RADIAL, |
| 180 | + use_mp: Optional[bool] = False, |
| 181 | + verbose: Optional[bool] = False, |
| 182 | + divider: Optional[int] = 2, |
| 183 | + shift_zero: Optional[float] = 1.0e-6, |
| 184 | + start_method: Optional[str] = None, |
180 | 185 | ): |
181 | 186 | r"""Computes the 1D acceptance at ``refpts`` observation points |
182 | 187 |
|
@@ -231,29 +236,44 @@ def get_1d_acceptance( |
231 | 236 | * When``use_mp=True`` all the available CPUs will be used. |
232 | 237 | This behavior can be changed by setting |
233 | 238 | ``at.DConstant.patpass_poolsize`` to the desired value |
| 239 | + * When multiple ``refpts`` are provided particles are first |
| 240 | + projected to the beginning of the ring with tracking. Then, |
| 241 | + all particles are tracked up to ``nturns``. This allows to |
| 242 | + do most of the work in a single function call and allows for |
| 243 | + full parallelization. |
234 | 244 | """ |
235 | 245 | if not use_mp: |
236 | 246 | grid_mode = GridMode.RECURSIVE |
237 | | - assert len(numpy.atleast_1d(plane)) == 1, \ |
238 | | - '1D acceptance: single plane required' |
239 | | - assert numpy.isscalar(resolution), '1D acceptance: scalar args required' |
240 | | - assert numpy.isscalar(amplitude), '1D acceptance: scalar args required' |
241 | | - npoint = numpy.ceil(amplitude/resolution) |
| 247 | + assert len(numpy.atleast_1d(plane)) == 1, "1D acceptance: single plane required" |
| 248 | + assert numpy.isscalar(resolution), "1D acceptance: scalar args required" |
| 249 | + assert numpy.isscalar(amplitude), "1D acceptance: scalar args required" |
| 250 | + npoint = numpy.ceil(amplitude / resolution) |
242 | 251 | if grid_mode is not GridMode.RECURSIVE: |
243 | | - assert npoint > 1, \ |
244 | | - 'Grid has only one point: increase amplitude or reduce resolution' |
245 | | - b, s, g = get_acceptance(ring, plane, npoint, amplitude, |
246 | | - nturns=nturns, dp=dp, refpts=refpts, |
247 | | - grid_mode=grid_mode, use_mp=use_mp, |
248 | | - verbose=verbose, start_method=start_method, |
249 | | - divider=divider, shift_zero=shift_zero, |
250 | | - offset=offset) |
| 252 | + assert ( |
| 253 | + npoint > 1 |
| 254 | + ), "Grid has only one point: increase amplitude or reduce resolution" |
| 255 | + b, s, g = get_acceptance( |
| 256 | + ring, |
| 257 | + plane, |
| 258 | + npoint, |
| 259 | + amplitude, |
| 260 | + nturns=nturns, |
| 261 | + dp=dp, |
| 262 | + refpts=refpts, |
| 263 | + grid_mode=grid_mode, |
| 264 | + use_mp=use_mp, |
| 265 | + verbose=verbose, |
| 266 | + start_method=start_method, |
| 267 | + divider=divider, |
| 268 | + shift_zero=shift_zero, |
| 269 | + offset=offset, |
| 270 | + ) |
251 | 271 | return numpy.squeeze(b), s, g |
252 | 272 |
|
253 | 273 |
|
254 | | -def get_horizontal_acceptance(ring: Lattice, |
255 | | - resolution: float, amplitude: float, |
256 | | - *args, **kwargs): |
| 274 | +def get_horizontal_acceptance( |
| 275 | + ring: Lattice, resolution: float, amplitude: float, *args, **kwargs |
| 276 | +): |
257 | 277 | r"""Computes the 1D horizontal acceptance at ``refpts`` observation points |
258 | 278 |
|
259 | 279 | See :py:func:`get_acceptance` |
@@ -306,13 +326,18 @@ def get_horizontal_acceptance(ring: Lattice, |
306 | 326 | * When``use_mp=True`` all the available CPUs will be used. |
307 | 327 | This behavior can be changed by setting |
308 | 328 | ``at.DConstant.patpass_poolsize`` to the desired value |
| 329 | + * When multiple ``refpts`` are provided particles are first |
| 330 | + projected to the beginning of the ring with tracking. Then, |
| 331 | + all particles are tracked up to ``nturns``. This allows to |
| 332 | + do most of the work in a single function call and allows for |
| 333 | + full parallelization. |
309 | 334 | """ |
310 | | - return get_1d_acceptance(ring, 'x', resolution, amplitude, *args, **kwargs) |
| 335 | + return get_1d_acceptance(ring, "x", resolution, amplitude, *args, **kwargs) |
311 | 336 |
|
312 | 337 |
|
313 | | -def get_vertical_acceptance(ring: Lattice, |
314 | | - resolution: float, amplitude: float, |
315 | | - *args, **kwargs): |
| 338 | +def get_vertical_acceptance( |
| 339 | + ring: Lattice, resolution: float, amplitude: float, *args, **kwargs |
| 340 | +): |
316 | 341 | r"""Computes the 1D vertical acceptance at refpts observation points |
317 | 342 |
|
318 | 343 | See :py:func:`get_acceptance` |
@@ -365,13 +390,18 @@ def get_vertical_acceptance(ring: Lattice, |
365 | 390 | * When``use_mp=True`` all the available CPUs will be used. |
366 | 391 | This behavior can be changed by setting |
367 | 392 | ``at.DConstant.patpass_poolsize`` to the desired value |
| 393 | + * When multiple ``refpts`` are provided particles are first |
| 394 | + projected to the beginning of the ring with tracking. Then, |
| 395 | + all particles are tracked up to ``nturns``. This allows to |
| 396 | + do most of the work in a single function call and allows for |
| 397 | + full parallelization. |
368 | 398 | """ |
369 | | - return get_1d_acceptance(ring, 'y', resolution, amplitude, *args, **kwargs) |
| 399 | + return get_1d_acceptance(ring, "y", resolution, amplitude, *args, **kwargs) |
370 | 400 |
|
371 | 401 |
|
372 | | -def get_momentum_acceptance(ring: Lattice, |
373 | | - resolution: float, amplitude: float, |
374 | | - *args, **kwargs): |
| 402 | +def get_momentum_acceptance( |
| 403 | + ring: Lattice, resolution: float, amplitude: float, *args, **kwargs |
| 404 | +): |
375 | 405 | r"""Computes the 1D momentum acceptance at refpts observation points |
376 | 406 |
|
377 | 407 | See :py:func:`get_acceptance` |
@@ -424,9 +454,13 @@ def get_momentum_acceptance(ring: Lattice, |
424 | 454 | * When``use_mp=True`` all the available CPUs will be used. |
425 | 455 | This behavior can be changed by setting |
426 | 456 | ``at.DConstant.patpass_poolsize`` to the desired value |
| 457 | + * When multiple ``refpts`` are provided particles are first |
| 458 | + projected to the beginning of the ring with tracking. Then, |
| 459 | + all particles are tracked up to ``nturns``. This allows to |
| 460 | + do most of the work in a single function call and allows for |
| 461 | + full parallelization. |
427 | 462 | """ |
428 | | - return get_1d_acceptance(ring, 'dp', resolution, amplitude, |
429 | | - *args, **kwargs) |
| 463 | + return get_1d_acceptance(ring, "dp", resolution, amplitude, *args, **kwargs) |
430 | 464 |
|
431 | 465 |
|
432 | 466 | Lattice.get_acceptance = get_acceptance |
|
0 commit comments