How To Guides
To simplify the scripting, especially when repetitive, there is the possibility to write recipe for raypyng, to perform simulations, and automatize some tasks.
Write your own Recipe
Recipe Template
This the template to use to write a recipe.
At the beginning of the file import
SimulationRecipe from raypyng
and define a the Simulation class as an empty dummy.
This will ensure that you have access to all the methods of the
Simulation class.
A recipe should containe at least the __init__()
method and three more methods: params(),
and simulation_name(),
and they must have as an argument the simulate class.
Compose the simulation parameters in the params method:
The simulation parameter must return a list of dictionaries,
where the keys of the dictionaries are parameters of on abject
present in the beamline, instances of ParamElement class.
The items of the dictionary must be the values that the parameter should
assume for the simulations.
Compose the simulation parameters in the params() method:
The params() method must return a list of dictionaries.
The keys of the dictionaries are parameters of on abject
present in the beamline, instances of ParamElement class.
The items of the dictionary must be the values that the parameter should
assume for the simulations.
Compose the export parameters in the exports() method:
The The exports() method must return a list of dictionaries,
method must return a list of dictionaries.
The keys of the dictionaries are parameters of on abject
present in the beamline, instances of ParamElement class.
The items of the dictionary is the name of the file that you want to export
(print the output of Simulation.possible_exports and
possible_exports_without_analysis.
Define the name to give to the simulation folder
in simulation_name()
from raypyng.recipes import SimulationRecipe
class Simulate: pass
class MyRecipe(SimulationRecipe):
def __init__(self):
pass
def params(self,sim:Simulate):
params = []
return params
def exports(self,sim:Simulate):
exports = []
return exports
def simulation_name(self,sim:Simulate):
self.sim_folder = ...
return self.sim_folder
How To Write a Recipe
An example of how to write a recipe that exports file for each element present in the beamline automatically.
class ExportEachElement(SimulationRecipe): """At one defined energy export a file for each optical elements """ def __init__(self, energy:float,/,nrays:int=None,sim_folder:str=None): """ Args: energy_range (np.array, list): the energies to simulate in eV nrays (int): number of rays for the source sim_folder (str, optional): the name of the simulation folder. If None, the rml filename will be used. Defaults to None. """ if not isinstance(energy, (int,float)): raise TypeError('The energy must be an a int or float, while it is a', type(energy)) self.energy = energy self.nrays = nrays self.sim_folder = sim_folder def params(self,sim:Simulate): params = [] # find source and add to param with defined user energy range found_source = False for oe in sim.rml.beamline.children(): if hasattr(oe,"photonEnergy"): self.source = oe found_source = True break if found_source!=True: raise AttributeError('I did not find the source') params.append({self.source.photonEnergy:self.energy}) # set reflectivity to 100% for oe in sim.rml.beamline.children(): for par in oe: try: params.append({par.reflectivityType:0}) except: pass # all done, return resulting params return params def exports(self,sim:Simulate): # find all the elements in the beamline oe_list=[] for oe in sim.rml.beamline.children(): oe_list.append(oe) # compose the export list of dictionaries exports = [] for oe in oe_list: exports.append({oe:'RawRaysOutgoing'}) return exports def simulation_name(self,sim:Simulate): if self.sim_folder is None: return 'ExportEachElement' else: return self.sim_folder if __name__ == "__main__": from raypyng import Simulate import numpy as np import os rml_file = ('rml_file.rml') sim = Simulate(rml_file, hide=True) sim.analyze = False myRecipe = ExportEachElement(energy=1000,nrays=10000,sim_folder='MyRecipeTest') # test resolving power simulations sim.run(myRecipe, multiprocessing="auto", force=True)
How to work with Undulator File
The WaveHelper class helps to inspect a WAVE simulation folder and provides a simple way to extract the absolute path of the simulation files to feed to the Undulator File. In this example we use the WAVE folder provided in the example folder at this link. Inside the folder there are WAVE simulation files for the first, third and fifth harmonic, and the Undulator is called U49
import numpy as np
from raypyng.wave_helper import WaveHelper
WH = WaveHelper(wave_folder_path='WAVE', harmonic=3, undulator='U49')
WH.report_available_energies(verbose=True)
This produces the following output:
I found the following harmonics: dict_keys([1, 3, 5])
the energy points for each harmonic are equally spaced
Harmonic number 1, available energies:
start 80
stop 570
step 10
Harmonic number 3, available energies:
start 240
stop 1710
step 30
Harmonic number 5, available energies:
start 400
stop 2850
step 50
We can now extract the file location for all the energies or a subset of the energies available for the first harmonic of the undulator:
energies = np.arange(80,570,10)
energy_files = WH.convert_energies_to_file_list(1,energies)
energy_files contains the absolute path to the WAVE simulation file for each energy. This can be used to change the energy of an Undulator by calling the parameter undulatorFile.