@@ -165,21 +165,30 @@ def _RF_bucket_dist(n_particles):
165165
166166
167167def cut_distribution (distribution , is_accepted ):
168- """ Generate coordinates according to some distribution inside the region
169- specified by is_accepted. (Wrapper for distributions, based on RF_cut..)
168+ """Generate coordinates according to some distribution inside the
169+ region specified by where the function is_accepted returns 1.
170+ (Wrapper for distributions, based on RF_cut..)
170171 Args:
171- is_accepted: function taking two parameters (z,dp) and returns an
172- array [0,1] specifying whether the coordinate lies
173- inside the desired phase space volume. Possible sources
174- are the rfbucket.make_is_accepted(...)
175- sigma_z: std of the normally distributed z coordinates
176- sigma_dp: std of the normally distributed dp coordinates
172+ distribution: a function which takes the n_particles as a
173+ parameter and returns a list-like object
174+ containing a 2D phase space. result[0] should
175+ stand for the spatial, result[1] for the momentum
176+ coordinate
177+ is_accepted: function taking two parameters (z, dp)
178+ [vectorised as arrays] and returning a boolean
179+ specifying whether the coordinate lies
180+ inside the desired phase space volume. A possible
181+ source to provide such an is_accepted function
182+ is the RFBucket.make_is_accepted or
183+ generators.make_is_accepted_within_n_sigma .
177184 Returns:
178185 A matcher with the specified bucket properties (closure)
179186 """
180187 def _cut_distribution (n_particles ):
181- '''Removes all particles for which is_accepted(x,x') is false
182- and redistributes them until all lie inside the bucket
188+ '''Regenerates all particles which fall outside a previously
189+ specified phase space region (via the function is_accepted
190+ in generators.cut_distribution) until all generated particles
191+ have valid coordinates and momenta.
183192 '''
184193 z = np .zeros (n_particles )
185194 dp = np .zeros (n_particles )
@@ -196,6 +205,32 @@ def _cut_distribution(n_particles):
196205 return [z , dp ]
197206 return _cut_distribution
198207
208+ def make_is_accepted_within_n_sigma (epsn_rms , limit_n_rms , twiss_beta = 1 ):
209+ '''Closure creating an is_accepted function (e.g. for
210+ cut_distribution). The is_accepted function will return whether
211+ the canonical coordinate and momentum pair lies within the phase
212+ space region limited by the action value limit_n_rms * epsn_rms.
213+
214+ Coordinate u and momentum up are assumed to be connected to the
215+ amplitude J via the twiss_beta value,
216+ J = sqrt(u^2 + twiss_beta^2 up^2) .
217+ The amplitude is required to be below the limit to be accepted,
218+ J < limit_n_rms * epsn_rms.
219+ The usual use case will be generating u and up in normalised Floquet
220+ space (i.e. before the normalised phase space coordinates
221+ get matched to the optics or longitudinal eta and Qs).
222+ In this case, twiss_beta takes the default value 1 in normalised
223+ Floquet space. Consequently, the 1 sigma RMS reference value
224+ epsn_rms corresponds to the normalised 1 sigma RMS emittance
225+ (i.e. amounting to beam.epsn_x() and beam.epsn_y() in the transverse
226+ plane, and beam.epsn_z()/4 in the longitudinal plane).
227+ '''
228+ threshold_amplitude_squared = (limit_n_rms * epsn_rms )** 2
229+ def is_accepted (u , up ):
230+ Jsq = u ** 2 + (twiss_beta * up )** 2
231+ return Jsq < threshold_amplitude_squared
232+ return is_accepted
233+
199234
200235class ParticleGenerator (Printing ):
201236 '''Factory to generate Particle instances according to distributions
0 commit comments