-
Notifications
You must be signed in to change notification settings - Fork 14
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
Add space-charge to Cheetah #142
Conversation
… of all the IGF solver functions.
Co-authored-by: Remi Lehe <remi.lehe@normalesup.org>
…ed. The code is not yet tested. (last test E+vB field)
…test (expansion of a cold uniform beam).
cheetah/accelerator.py
Outdated
@@ -299,6 +307,356 @@ def defining_features(self) -> list[str]: | |||
def __repr__(self) -> str: | |||
return f"{self.__class__.__name__}(length={repr(self.length)})" | |||
|
|||
class SpaceChargeKick(Element): | |||
""" | |||
Simulates space charge effects on a beam. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think at some point in the future, we should think about creating a Effects
class and make SpaceChargeKick
a subclass of that. But right now this doesn't make sense yet.
Nevertheless, here is how I think we should integrate adding space charge to elements right now in a way that can easily be extended in the future:
Basically what I would do is to add a method to the Element
class that looks something like this:
class Element:
...
def with_space_charge(self, resolution: float = 0.01, *args, **kwargs) -> Segment:
splits = self.split(resolution)
splits_with_space_charge = # List of [split, sc, split, sc, ..., split, sc] ... probably itertools has a nice way to create this ... *args and **kwargs go into SpaceChargeKick
return Segment(elements=splits_with_space_charge, name=f"{self.name}_with_space_charge")
This should end up looking similar to what @RemiLehe proposed in the very beginning. So if you do
Drift(length=0.5, name="my_drift").with_space_charge(resolution=0.25, nx=64)
you get
Segment(
name="my_drift_with_space_charge",
elements=[
Drift(length=0.25), SpaceChargeKick(nx=64), Drift(length=0.25), SpaceChargeKick(nx=64)
],
)
This example is probably not quite correct in many ways, but I think it illustrates my idea.
The nice thing about doing it this way would be that it automatically works for all elements that implement split
correctly, and that it would be relatively straightforward to extend this for other collective effects in the future.
Does this make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An alternative thought for the low level implementation: One could also create sub- or mixing classes for thin (L=0) and thick (L>0) elements. For elements in ImpactX, we currently use these mixin classes, e.g. Drift vs. thin Multipole.
Space charge kicks could be thin elements :)
For the high level interface, I agree on the above syntax. You want to automatically slice this up, a property or method on how many slices on the sliced element is a nice user interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for this PR!
I added a few suggestions ; we can discuss them further offline.
Weirdly all GitHub Actions except for the docs build are currently not showing up on this PR. We need to keep an eye on this. It could just be a result of the merge conflicts with |
Co-authored-by: Remi Lehe <remi.lehe@normalesup.org>
Co-authored-by: Remi Lehe <remi.lehe@normalesup.org>
@cr-xu Yes, that is correct. The way in which we apply the space-charge kicks can be seen as an instance of Strang splitting, which under reasonable conditions, is second-order accurate which respect to the length of the splitting intervals. |
def _deposit_charge_on_grid( | ||
self, | ||
beam: ParticleBeam, | ||
moments: torch.Tensor, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would suggest to replace the term moments
by something like xp_coordinates
or beam_coordinates
, or something similar, throughout the code.
The problem with moments
is that it suggests either the idea of moments of a distribution (mean, rms, etc.), or the idea of momentum (px, py, pz). None of these are correct descriptions of what this array contains.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@RemiLehe this will probably also have to be done in particle_beam.py
, including maybe a rephrasing of the docstrings (?).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. Done in b2e45c0
So, it turns out scipy I guess this one early sign that |
🎉 |
Description
Adds a new
SpaceChargeKick
element that enables adding space charge to any other elements.Motivation and Context
Implements #137.
See #137
Types of changes
Checklist
flake8
(required).pytest
tests pass (required).pytest
on a machine with a CUDA GPU and made sure all tests pass (required).Note: We are using a maximum length of 88 characters per line