Source code for crystalpy.util.PhotonBunch

"""
A stack of photons, each one characterized by energy and direction.
"""
import numpy
import copy
import scipy.constants as codata

from crystalpy.util.Vector import Vector
from crystalpy.util.Photon import Photon

#todo: delete
[docs]class PhotonBunchOld(object): """ The PhotonBunch is Photon stack instances, making up the photon bunch or beam. Constructor. Parameters ---------- photons : list List of Photon instances. """ def __init__(self, photons=None): if photons == None: self.polarized_photon_bunch = [] else: self.polarized_photon_bunch = photons
[docs] @classmethod def initialize_from_energies_and_directions(cls, energies, V): """Construct a bunch from arrays with photon energies and directions Parameters ---------- energies : list, numpy array V : Vector instance (with a tack of vectors) Returns ------- PhotonBunch instance """ if V.nStack() != energies.size: raise Exception("incompatible inputs") bunch = PhotonBunchOld() for i in range(energies.size): bunch.addPhoton(Photon(energy_in_ev=energies[i], direction_vector=V.extractStackItem(i))) return bunch
[docs] def energies(self): """Return the energies of the photons. Returns ------- numpy array The energies of the photons (copied, not referenced). """ energies = numpy.zeros(len(self)) for i,photon in enumerate(self): energies[i] = photon.energy() # Photon.energy() return energies
[docs] def energy(self): # just in case """Return the energies of the photons. Returns ------- numpy array The energies of the photons (copied, not referenced). """ return self.energies()
[docs] def wavelength(self): """Return the wavelengths of the photons (in m). Returns ------- numpy array The wavelengths of the photons. """ E_in_Joule = self.energies() * codata.e # elementary_charge # Wavelength in meter wavelength = (codata.c * codata.h / E_in_Joule) return wavelength
[docs] def wavenumber(self): """Return the wavenumbers of the photons (in m^-1). Returns ------- numpy array The wavenumbers of the photons. """ return (2.0 * numpy.pi) / self.wavelength()
[docs] def unitDirectionVector(self): """Return the directions of the photons. Returns ------- Vector instance The directions in stacked vectors. """ X = numpy.zeros(len(self)) Y = numpy.zeros(len(self)) Z = numpy.zeros(len(self)) for i,photon in enumerate(self): cc = photon.unitDirectionVector().components() X[i] = cc[0] Y[i] = cc[1] Z[i] = cc[2] return Vector.initializeFromComponents([X, Y, Z])
[docs] def wavevector(self): """Return the wavevectors of the photons. Returns ------- Vector instance The wavevectors in stacked vectors. """ return self.unitDirectionVector().scalarMultiplication(self.wavenumber())
[docs] def duplicate(self): """Return a clone of the PhotonBunch instance. Returns ------- PhotonBunch instance """ return copy.deepcopy(self)
[docs] def setUnitDirectionVector(self, vector): """Sets the directions of the photons. Parameters ---------- vector : Vector instance Stack of vectors with the directions. """ for i,photon in enumerate(self): photon._unit_direction_vector = vector.extractStackItem(i)
# # extend these methods when heritating from Photon #
[docs] def toDictionary(self): """Created a dictionary containing information about the bunch. Returns ------- dict Information in tags: "number of photons", "energies", "deviations", "vx", "vy" and "vz". """ array_dict = dict() energies = numpy.zeros(len(self)) deviations = numpy.zeros(len(self)) directions = numpy.zeros([3, len(self)]) i = 0 for i,photon in enumerate(self): energies[i] = photon.energy() # Photon.energy() deviations[i] = photon.deviation() directions[0, i] = photon.unitDirectionVector().components()[0] directions[1, i] = photon.unitDirectionVector().components()[1] directions[2, i] = photon.unitDirectionVector().components()[2] i += 1 # todo: very bizarre.... remove? array_dict["number of photons"] = i array_dict["energies"] = energies array_dict["deviations"] = deviations array_dict["vx"] = directions[0, :] array_dict["vy"] = directions[1, :] array_dict["vz"] = directions[2, :] return array_dict
[docs] def toString(self): """Returns a string containing the parameters characterizing each photon in the bunch.""" bunch_string = str() for photon in self: string_to_attach = str(photon.energy()) + " " + \ photon.unitDirectionVector().toString() + "\n" bunch_string += string_to_attach return bunch_string
# # end of methods to be extended #
[docs] def addPhoton(self, to_be_added): """Adds a photon to the bunch. Parameters ---------- to_be_added : Photon instance """ self.polarized_photon_bunch.append(to_be_added)
[docs] def addPhotonsFromList(self, to_be_added): """Adds a list of photons to the bunch. Parameters ---------- to_be_added : list The photons to be added """ self.polarized_photon_bunch.extend(to_be_added)
[docs] def addBunch(self, to_be_added): """Adds photons in a PhotonBunch instance. Parameters ---------- to_be_added : PhotonBunch instance Photons to be added. """ self.polarized_photon_bunch.extend(to_be_added.getListOfPhotons())
[docs] def getNumberOfPhotons(self): """Returns the number of photons in the bunch. Returns ------- int Number of photons. """ return len(self.polarized_photon_bunch)
[docs] def getListOfPhotons(self): """Returns a list with the photons in the bunch. Returns ------- list List with photons. """ return self.polarized_photon_bunch
[docs] def getPhotonIndex(self,index): """Returns the photon in the bunch with a given index. Parameters ---------- index : int The photon index to be referenced. Returns ------- Photon instance The photon (referenced, not copied). """ return self.polarized_photon_bunch[index]
[docs] def setPhotonIndex(self,index,polarized_photon): """Sets the photon in the bunch with a given index. Parameters ---------- index : int The photon index to be modified. polarized_photon : Photon instance The photon to be stored. """ self.polarized_photon_bunch[index] = polarized_photon
[docs] def keys(self): """return the keys of the dictionary resulting from toDictionary method""" return self.toDictionary().keys()
[docs] def getArrayByKey(self, key): """Returns the array of a givem key in from toDictionary method Parameters ---------- key : deviations', 's0', 's1', 's2', 's3'. Returns ------- numpy array """ return self.toDictionary()[key]
[docs] def isMonochromatic(self, places): """Inquires about bunch monochromaticity. Parameters ---------- places : number of decimal places to be taken into account for comparing energies. Returns ------- bool True if all photons in the bunch have the same energy. """ first_energy = round(self.polarized_photon_bunch[0].energy(), places) # if the first element has the same energy as all others, then all others share the same energy value. for photon in self: if first_energy != round(photon.energy(), places): return False return True
[docs] def isUnidirectional(self): """Inquires if all photons in the bunch have the same direction. Returns ------- bool True if all photons have the same direction. """ first_direction = self.polarized_photon_bunch[0].unitDirectionVector() # Vector object. # if the first element goes the same direction as all others, then all others share the same direction. for photon in self: if first_direction != photon.unitDirectionVector(): # the precision is set to 7 decimal places. return False return True
def __len__(self): return len(self.polarized_photon_bunch) def __iter__(self): return iter(self.polarized_photon_bunch) def __getitem__(self, key): return self.polarized_photon_bunch[key]
# # #
[docs]class PhotonBunchDecorator(object):
[docs] def energies(self): """Return the energies of the photons. Returns ------- numpy array The energies of the photons (copied, not referenced). """ return self.energy()
[docs] def toString(self): """Returns a string table containing the energy and direction vector for each photon in the bunch.""" bunch_string = str() for photon in self: string_to_attach = str(photon.energy()) + " (" + \ photon.unitDirectionVector().toString() + ")\n" bunch_string += string_to_attach return bunch_string
[docs] def addPhotonsFromList(self, to_be_added): """Adds a list of photons to the bunch. Parameters ---------- to_be_added : list The photons to be added """ for el in to_be_added: self.addPhoton(el)
[docs] def addBunch(self, to_be_added): """Adds photons in a PhotonBunch instance. Parameters ---------- to_be_added : PhotonBunch instance Photons to be added. """ self.addPhoton(to_be_added)
[docs] def getNumberOfPhotons(self): """Returns the number of photons in the bunch. Returns ------- int Number of photons. """ return self.unitDirectionVector().nStack()
[docs] def getListOfPhotons(self): """Returns a list with the photons in the bunch. Returns ------- list List with photons. """ out = [] for i in range(self.getNumberOfPhotons()): out.append(self.getPhotonIndex(i)) return out
[docs] def keys(self): """return the keys of the dictionary resulting from toDictionary method""" return self.toDictionary().keys()
[docs] def getArrayByKey(self, key): """Returns the array of a givem key in from toDictionary method Parameters ---------- key : deviations', 's0', 's1', 's2', 's3'. Returns ------- numpy array """ return self.toDictionary()[key]
[docs] def isMonochromatic(self, places): """Inquires about bunch monochromaticity. Parameters ---------- places : number of decimal places to be taken into account for comparing energies. Returns ------- bool True if all photons in the bunch have the same energy. """ return numpy.all(self.energy() == self.energy()[0])
[docs] def isUnidirectional(self): """Inquires if all photons in the bunch have the same direction. Returns ------- bool True if all photons have the same direction. """ first_direction = self.getPhotonIndex(0).unitDirectionVector() # Vector object. # if the first element goes the same direction as all others, then all others share the same direction. for i in range(self.getNumberOfPhotons()): if first_direction != self.getPhotonIndex(i).unitDirectionVector(): # the precision is set to 7 decimal places. return False return True
def __len__(self): return self.getNumberOfPhotons() def __iter__(self): return iter(self.getListOfPhotons()) # # these ones will be updated in ComplexAmplitudePhotonBunch and PolirizedPhotonBunch #
[docs] def toDictionary(self): """Created a dictionary containing information about the bunch. Returns ------- dict Information in tags: "number of photons", "energies", "deviations", "vx", "vy" and "vz". """ array_dict = dict() e = self.energy() v = self.unitDirectionVector() n = v.nStack() array_dict["number of photons"] = n array_dict["energies"] = e array_dict["deviations"] = self.deviation() array_dict["vx"] = v.components()[0] array_dict["vy"] = v.components()[1] array_dict["vz"] = v.components()[2] return array_dict
[docs] def addPhoton(self, to_be_added): """Adds a photon to the bunch. Parameters ---------- to_be_added : Photon instance """ self.setEnergy(numpy.append(self.energy(), to_be_added.energy())) self.setUnitDirectionVector(self.unitDirectionVector().concatenate(to_be_added.unitDirectionVector()))
[docs] def getPhotonIndex(self, index): """Returns the photon in the bunch with a given index. Parameters ---------- index : int The photon index to be referenced. Returns ------- Photon instance The photon (referenced, not copied). """ v = self.unitDirectionVector() vx = v.components()[0] vy = v.components()[1] vz = v.components()[2] return Photon(energy_in_ev=self.energy()[index], direction_vector=Vector(vx[index], vy[index], vz[index]))
[docs] def setPhotonIndex(self, index, polarized_photon): """Sets the photon in the bunch with a given index. Parameters ---------- index : int The photon index to be modified. polarized_photon : Photon instance The photon to be stored. """ energy = self.energy() v = self.unitDirectionVector() vx = v.components()[0] vy = v.components()[1] vz = v.components()[2] energy[index] = polarized_photon.energy() vx[index] = polarized_photon.unitDirectionVector().components()[0] vy[index] = polarized_photon.unitDirectionVector().components()[1] vz[index] = polarized_photon.unitDirectionVector().components()[2] self.setEnergy(energy) self.setUnitDirectionVector(Vector(vx, vy, vz))
[docs]class PhotonBunch(Photon, PhotonBunchDecorator): """ The PhotonBunch is a Photon stack. It inheritates from Photon and uses stacks for more efficient stockage. Additional methods useful for stacks or bunches are defined in PhotonBunchDecorator. Constructor. Parameters ---------- photons : list List of Photon instances. """ def __init__(self, photons=None): if photons == None: super().__init__(energy_in_ev=[], direction_vector=Vector([],[],[])) else: n = len(photons) energy = numpy.zeros(n) for i,el in enumerate(photons): energy[i] = el.energy() vv = photons[i].unitDirectionVector() if i == 0: v = Vector( vv.components()[0], vv.components()[1], vv.components()[2], ) else: v.append(vv) self.setEnergy(energy) self.setUnitDirectionVector(v) super().__init__(energy_in_ev=energy, direction_vector=v)
[docs] @classmethod def initializeFromPhoton(cls, photon_stack): """Construct a bunch from a photon stack. Parameters ---------- photon_stack : instance of Photon Returns ------- PhotonBunch instance """ out = PhotonBunch() out.setEnergy(photon_stack.energy()) out.setUnitDirectionVector(photon_stack.unitDirectionVector()) return out
[docs] @classmethod def initializeFromArrays(cls, energy=[], vx=[], vy=[], vz=[]): """Construct a bunch from arrays with photon energies and directions. Parameters ---------- energies : list, numpy array the array with photon energy in eV. vx : list, numpy array the array with X component of the direction vector. vy : list, numpy array the array with Y component of the direction vector. vz : list, numpy array the array with Z component of the direction vector. Returns ------- PhotonBunch instance """ bunch = PhotonBunch() bunch.setEnergy(numpy.array(energy)) bunch.setUnitDirectionVector(Vector(numpy.array(vx), numpy.array(vy), numpy.array(vz))) return bunch
if __name__ == "__main__": npoint = 10 vx = numpy.zeros(npoint) + 0.0 vy = numpy.zeros(npoint) + 1.0 vz = numpy.zeros(npoint) + 2.0 energy = numpy.zeros(npoint) + 3000.0 photon_bunch1 = PhotonBunch() # # loop # photons_list = [] for i in range(npoint): photon = Photon(energy_in_ev=energy[i], direction_vector=Vector(vx[i], vy[i], vz[i])) photon_bunch1.addPhoton(photon) photons_list.append(photon) photon_bunch2 = PhotonBunch(photons_list) # # vector # photon_stack = Photon(energy, Vector(vx, vy, vz)) photon_bunch3 = PhotonBunch().initializeFromPhoton(photon_stack) photon_bunch4 = PhotonBunch().initializeFromArrays(energy=energy, vx=vx, vy=vy, vz=vz) # # check # print(">>>>>>>>>>>>>>>>>> 1") print(photon_bunch1.toDictionary()) print(">>>>>>>>>>>>>>>>>> 2") print(photon_bunch2.toDictionary()) print(">>>>>>>>>>>>>>>>>> 3") print(photon_bunch3.toDictionary()) print(">>>>>>>>>>>>>>>>>> 4") print(photon_bunch4.toDictionary())