hightower8083 / synchrad

Synchrotron Radiation calculator via openCL
GNU General Public License v3.0
18 stars 11 forks source link

Single trace evaluation #22

Closed TheresaBruemmer closed 1 year ago

TheresaBruemmer commented 2 years ago

Hi @hightower8083,

I recently started using synchrad for ICS calculations and enjoy it very much, especially the ease/elegance with which it can be combined with other python-based code. Before, I used clara2 (https://github.com/ComputationalRadiationPhysics/clara2.git). A very useful tool in clara2, I found, is the option to obtain the classical radiation emitted by each macroparticle. This allows for great diagnostics, extracting the dependence of the contribution to the full spectrum on certain particle parameters. It would be of high interest to me, if this could be implemented in your code, as well.

hightower8083 commented 2 years ago

Hi @TheresaBruemmer

Thank you a lot for you interest in the code, and I'm glad that it serves you in your work. I'm well familiar with the clara2 project and its devs -- as far as I know they use some specific NUFFT libs and on CPU its probably faster than synchrad, though I've never used it myself.

Concerning your need, I'm not sure what is the problem with the single track simulation -- this option does not require any additional features. In the simplest interactive mode (without files I/O), the code takes the list of tracks:

calc.calculate_spectrum( particleTracks=tracks, timeStep=your_dt )

and this list may as well contain a single track. In fact, the Undulator_Example actually uses a single particle track for the classical undulator radiation (Np = 1 in cell [2]).

If you need to make a series of single track calculations, the easiest would be to run it in a loop and record results into the individual files, e.g.

for i_track, track in enumerate(tracks):
    calc.calculate_spectrum( particleTracks=[track,], 
                             timeStep=your_dt, 
                             file_spectrum=f'spectrum_{i_track}.h5')

After that you'll be able to load the obtained spectra one by one for the analysis,

for i_track in range(len(tracks)):
    calc = SynchRad(file_spectrum=f'spectrum_{i_track}.h5')
    ***your analysis code using calc.get_... methods***

Let me know if this is helpful and do not hesitate to ask for more advises.

TheresaBruemmer commented 2 years ago

Hi @hightower8083, thank you for your answer! That is definitely a good option to approach the single trace evaluation for now.

However, if I understand correctly, parameters such as Data['radiation'] would then be overwritten for each track, right? For me, it would be of interest to have the full spec info and the single traces on top of that, but without running the calculation twice, i.e. as

for i_track, track in enumerate(tracks):
    calc.calculate_spectrum( particleTracks=[track,], 
                             timeStep=your_dt, 
                             file_spectrum=f'spectrum_{i_track}.h5')
calc.calculate_spectrum( particleTracks=tracks, 
                             timeStep=your_dt, 
                             file_spectrum='spectrum.h5')

Since for incoherent radiation, the total radiation is the sum of the single contributions. The function calc.calculate_spectrum( particleTracks=tracks, timeStep=your_dt ) then calculates the single contributions and adds them up. So the info I want is already generated, but not saved. That also means, I could generate the single spectra and add them up. But it would be nicer to have a boolean in the original function that gives out the single trace spectra data.

Thank you so much for your help

hightower8083 commented 2 years ago

Hi again @TheresaBruemmer

Indeed Data['radiation'] is re-initialised each time the calculate_spectrum method is called. For this reason, in the example above I've suggested to save each track calculation to a file via the argument file_spectrum=f'spectrum_{i_track}.h5', so that the spectra will be safely recorded in the individual files. After that, the obtained ensemble of files spectrum_1.h5, spectrum_2.h5 ..., will have the full information you need, and you could post-process a full spectrum by the sum

spectrum_full = 0
for i_track in range(len(tracks)):
    calc = SynchRad(file_spectrum=f'spectrum_{i_track}.h5')
    spectrum_full += calc.get_full_spectrum(***relevant arguments like lambda0_um***)

Note that each time you the constructor calc = SynchRad(file_spectrum=f'spectrum_{i_track}.h5') is invoked, it'll reload the Data['radiation'] from the file corresponding to the track. If you wish to have obtain the calc object with the full spectrum (to use the included post-processing methods), you may overwrite this field with the obtained sum via:

calc.Data['radiation']['total'][0][:] = spectrum_full

NB: in this line I assume you consider calculate_spectrum method with default arguments comp='total'and nSnaps=1.

I understand your idea to have a simulation that would keep individual spectra as well as the sum, but this would involve lots of 3D datasets (one per track) potentially kept in the memory. In my typical sychrad calculations I consider thousands (even tens of thousands) of tracks and this option will never be of use. On the other hand, damping the spectra to the files for each track of interest would lead to the same result and keep the code relatively simple. Moreover, while the suggested modification will surely require a significant code revision affecting other options, like nSnaps>1 for tracking the dynamics (already produces multiple datasets) , field complex sums comp='cartesian_complex' for coherent radiation etc.

I hope this file-based approach can address your needs. Otherwise, you may send some simplified example (e.g. jupyter notebook) of what you are trying to do, or we could schedule a zoom, so I could guide you further with your particular case.