def testDuplicate(self):
        ph1 = PolarizedPhoton(8000.0, Vector(2, 4, 5),
                              StokesVector([1, 2, 3, 4]))
        ph2 = ph1.duplicate()

        assert_array_almost_equal(ph1.stokesVector().components(),
                                  ph2.stokesVector().components())

        assert_array_almost_equal(ph1.unitDirectionVector().components(),
                                  ph2.unitDirectionVector().components())
    def testConstructor(self):
        photon = PolarizedPhoton(energy_in_ev=8000,
                                 direction_vector=Vector(0.0, 1.0, 0.0),
                                 stokes_vector=StokesVector(
                                     [1.0, 0.0, 1.0, 0.0]))

        self.assertIsInstance(photon, PolarizedPhoton)
        self.assertTrue(photon.unitDirectionVector() == Vector(0.0, 1.0, 0.0))
        self.assertTrue(
            photon.stokesVector() == StokesVector([1.0, 0.0, 1.0, 0.0]))
    def testInheritatedMethods(self):
        ph1 = PolarizedPhoton(8000.0, Vector(2, 4, 5),
                              StokesVector([1, 2, 3, 4]))

        ph1.setUnitDirectionVector(Vector(1, 0, 0))
        ph1.setEnergy(9000)

        self.assertTrue(ph1.unitDirectionVector().components()[0] == 1)
        self.assertTrue(ph1.unitDirectionVector().components()[1] == 0)
        self.assertTrue(ph1.unitDirectionVector().components()[2] == 0)

        self.assertTrue(ph1.energy() == 9000.0)
    def from_shadow_beam_to_photon_bunch(self):

        vx = self.incoming_shadow_beam._beam.getshcol(4, nolost=1)
        vy = self.incoming_shadow_beam._beam.getshcol(5, nolost=1)
        vz = self.incoming_shadow_beam._beam.getshcol(6, nolost=1)

        s0 = self.incoming_shadow_beam._beam.getshcol(30, nolost=1)
        s1 = self.incoming_shadow_beam._beam.getshcol(31, nolost=1)
        s2 = self.incoming_shadow_beam._beam.getshcol(32, nolost=1)
        s3 = self.incoming_shadow_beam._beam.getshcol(33, nolost=1)
        energies = self.incoming_shadow_beam._beam.getshcol(11, nolost=1)

        photon_bunch = PolarizedPhotonBunch([])
        photons_list = list()
        for i, energy in enumerate(energies):
            photon = PolarizedPhoton(
                energy_in_ev=energy,
                direction_vector=Vector(vx[i], vy[i], vz[i]),
                stokes_vector=StokesVector([s0[i], s1[i], s2[i], s3[i]]))
            #photon_bunch.add(photon)
            # print("<><> appending photon",i)
            photons_list.append(photon)

        photon_bunch.addPhotonsFromList(photons_list)

        return photon_bunch
    def testChangePhotonValue(self):
        nphotons = 10

        from crystalpy.util.Vector import Vector
        from crystalpy.util.StokesVector import StokesVector

        bunch = PolarizedPhotonBunch([])
        for i in range(nphotons):
            polarized_photon = PolarizedPhoton(
                energy_in_ev=1000.0 + i,
                direction_vector=Vector(0, 1.0, 0),
                stokes_vector=StokesVector([1.0, 0, 1.0, 0]))
            bunch.addPhoton(polarized_photon)

        # photon5_stokes = bunch.get_photon_index(5).stokesVector().get_array(numpy=True)
        # print("photon 5 stokes ",photon5_stokes)

        photon5 = bunch.getPhotonIndex(5)

        photon5.setStokesVector(StokesVector([1, 0, 0, 0]))
        photon5_stokes_new = bunch.getPhotonIndex(
            5).stokesVector().components()

        # print("photon 5 stokes new ",photon5_stokes_new)

        assert_almost_equal(photon5_stokes_new, numpy.array([1.0, 0, 0, 0]))
Exemple #6
0
    def calculateDiffractedPolarizedPhoton(self, diffraction_setup,
                                           incoming_polarized_photon,
                                           inclination_angle):
        """
        Calculates the diffraction/transmission given by the setup.
        :param diffraction_setup: The diffraction setup.
        :return: PhotonBunch object made up of diffracted/transmitted photons.
        """
        # Retrieve the incoming Stokes vector.
        incoming_stokes_vector = incoming_polarized_photon.stokesVector()

        # Get PerfectCrystal instance for the current photon.
        perfect_crystal = self._perfectCrystalForPhoton(
            diffraction_setup, incoming_polarized_photon)

        # Calculate diffraction for current incoming photon.
        complex_amplitudes = perfect_crystal.calculateDiffraction(
            incoming_polarized_photon)

        # Calculate outgoing Photon.
        outgoing_photon = perfect_crystal._calculatePhotonOut(
            incoming_polarized_photon)

        # Calculate intensities and phases of the crystal  reflectivities or transmitivities
        intensity_pi = complex_amplitudes["P"].intensity()
        intensity_sigma = complex_amplitudes["S"].intensity()
        phase_pi = complex_amplitudes["P"].phase()
        phase_sigma = complex_amplitudes["S"].phase()

        # Get a CrystalPhasePlate instance which contains the Mueller matrix
        phase_plate = CrystalPhasePlate(  #incoming_stokes_vector=incoming_stokes_vector,
            intensity_sigma=intensity_sigma,
            phase_sigma=phase_sigma,
            intensity_pi=intensity_pi,
            phase_pi=phase_pi,
            inclination_angle=inclination_angle)

        # Use intensities and phases to calculate the Stokes vector for the outgoing photon.
        outgoing_stokes_vector = phase_plate.calculate_stokes_vector(
            incoming_stokes_vector)

        # Piece together the PolarizedPhoton object.
        outgoing_polarized_photon = PolarizedPhoton(
            energy_in_ev=outgoing_photon.energy(),
            direction_vector=outgoing_photon.unitDirectionVector(),
            stokes_vector=outgoing_stokes_vector)

        return outgoing_polarized_photon
    def testFromArray(self):

        npoint = 1000
        vx = numpy.zeros(npoint) + 0.0
        vy = numpy.zeros(npoint) + 1.0
        vz = numpy.zeros(npoint) + 0.0

        s0 = numpy.zeros(npoint) + 1
        s1 = numpy.zeros(npoint) + 0
        s2 = numpy.zeros(npoint) + 1
        s3 = numpy.zeros(npoint) + 0

        energy = numpy.zeros(npoint) + 3000.0

        photon_bunch = PolarizedPhotonBunch([])

        photons_list = list()
        for i in range(npoint):

            photon = PolarizedPhoton(
                energy_in_ev=energy[i],
                direction_vector=Vector(vx[i], vy[i], vz[i]),
                stokes_vector=StokesVector([s0[i], s1[i], s2[i], s3[i]]))
            photons_list.append(photon)

        photon_bunch.addPhotonsFromList(photons_list)

        # print("<><><>",photon_bunch.toString())
        # print("<><><>",photon_bunch.toDictionary())

        self.assertTrue(1.0 == any(photon_bunch.getArrayByKey("s0")))
        self.assertTrue(0.0 == any(photon_bunch.getArrayByKey("s1")))
        self.assertTrue(1.0 == any(photon_bunch.getArrayByKey("s2")))
        self.assertTrue(0.0 == any(photon_bunch.getArrayByKey("s3")))

        energies = photon_bunch.getArrayByKey("energies")
        for energy in energies:
            self.assertAlmostEqual(energy, 3000.0)
Exemple #8
0
if __name__ == '__main__':
    from PyQt5.QtWidgets import QApplication

    from crystalpy.util.Vector import Vector
    from crystalpy.util.StokesVector import StokesVector
    from crystalpy.util.PolarizedPhoton import PolarizedPhoton
    from crystalpy.util.PolarizedPhotonBunch import PolarizedPhotonBunch

    app = QApplication([])
    ow = OWPhotonViewer()

    nphotons = 10

    from crystalpy.util.Vector import Vector
    from crystalpy.util.StokesVector import StokesVector

    bunch = PolarizedPhotonBunch([])
    for i in range(nphotons):
        polarized_photon = PolarizedPhoton(energy_in_ev=1000.0 + i,
                                           direction_vector=Vector(0, 1.0, 0),
                                           stokes_vector=StokesVector(
                                               [1.0, 0, 1.0, 0]))
        bunch.addPhoton(polarized_photon)

    ow._set_input(bunch)
    ow.do_plot()
    ow.show()

    app.exec_()
    ow.saveSettings()
Exemple #9
0
def stokes_calculator(energy,
                      deviations,
                      e_gev=6.04,
                      i_a=0.2,
                      hdiv_mrad=1.0,
                      ec_ev=19551.88):
    """
    Calculates the Stokes vectors for each PolarizedPhoton according to the theory of the BM emission.
    It does this by use of a modified version of the sync_ang function that allows the computation of the
    power densities for the RCP and LCP components on top of the linear components.
    The dW_+1 and dW_-1 values are obtained by setting respectively:

        l2 = l3 = 1/sqrt(2) for RCP and
        l2 = -l3 = 1/sqrt(2) for LCP.

    The computation of dW_-1 (LCP), dW_1 (RCP), dW_2 (sigma) and dW_3 (pi) makes it possible to use
    the formula 3.23 from Sokolov & Ternov for the phase difference delta = phi_3 - phi_2.
    This in turn lead to the Stokes parameters as defined in Jackson, 7.27.

    The default values for the parameters are the typical ESRF values.
    :param energy: desired photon energy in eV.
    :type energy: float
    :param deviations: array of angle deviations in milliradians.
    :type deviations: numpy.ndarray
    :param e_gev: energy of the electrons in GeV.
    :type e_gev: float
    :param i_a: beam current in A.
    :type i_a: float
    :param hdiv_mrad: horizontal divergence of the beam in milliradians.
    :type hdiv_mrad; float
    :param ec_ev: critical energy as in Green, pag.3.
    :type ec_ev: float
    :return: list of StokesVector objects.
    :rtype: PolarizedPhotonBunch
    """
    #
    # Calculate some parameters needed by sync_f (copied from sync_ang by Manuel Sanchez del Rio).
    # a8 = 1.3264d13
    #
    deviations = np.array(deviations)
    a8 = codata_ec / np.power(codata_mee, 2) / codata_h * (9e-2 / 2 / np.pi)
    energy = float(energy)
    eene = energy / ec_ev
    gamma = e_gev * 1e3 / codata_mee

    #
    # Calculate the power densities for the 4 cases:
    #
    #    -1 --> left circularly polarized       l2 = -l3 = 1/sqrt(2)
    #     1 --> right circularly polarized      l2 = l3 = 1/sqrt(2)
    #     2 --> linear sigma component          l2 = 1 & l3 = 0
    #     3 --> linear pi component             l3 = 1 & l2 = 0
    #
    left_circular = modified_sync_f(deviations * gamma / 1e3, eene, polarization=-1) * \
        np.power(eene, 2) * \
        a8 * i_a * hdiv_mrad * np.power(e_gev, 2)  # -1

    right_circular = modified_sync_f(deviations * gamma / 1e3, eene, polarization=1) * \
        np.power(eene, 2) * \
        a8 * i_a * hdiv_mrad * np.power(e_gev, 2)  # 1

    sigma_linear = modified_sync_f(deviations * gamma / 1e3, eene, polarization=2) * \
        np.power(eene, 2) * \
        a8 * i_a * hdiv_mrad * np.power(e_gev, 2)  # 2

    pi_linear = modified_sync_f(deviations * gamma / 1e3, eene, polarization=3) * \
        np.power(eene, 2) * \
        a8 * i_a * hdiv_mrad * np.power(e_gev, 2)  # 3

    #
    # Calculate the phase difference delta according to Sokolov, formula 3.23.
    #
    delta = (left_circular - right_circular) / \
        (2 * np.sqrt(sigma_linear * pi_linear))

    delta = np.arcsin(delta)

    #
    # Calculate the Stokes parameters.
    #
    s_0 = sigma_linear + pi_linear
    s_1 = sigma_linear - pi_linear
    s_2 = np.sqrt(sigma_linear) * np.sqrt(pi_linear) * np.cos(delta)
    s_3 = np.sqrt(sigma_linear) * np.sqrt(pi_linear) * np.sin(delta)
    s_2 *= 2  # TODO: try to understand why if I multiply by 2 in the line above I get a warning.
    s_3 *= 2

    #
    # Normalize the Stokes parameters.
    #
    # modulus = np.sqrt(s_0 ** 2 + s_1 ** 2 + s_2 ** 2 + s_3 ** 2)
    #
    # if np.any(modulus != 0):
    #     s_0 /= modulus
    #     s_1 /= modulus
    #     s_2 /= modulus
    #     s_3 /= modulus
    #
    # else:
    #     raise Exception("BendingMagnet.stokes_calculator: Stokes vector is null vector!\n")

    maximum = np.max(s_0)
    s_0 /= maximum
    s_1 /= maximum
    s_2 /= maximum
    s_3 /= maximum

    # Following XOP conventions, the photon bunch travels along the y axis in the lab frame of reference.
    base_direction = Vector(0, 1, 0)
    rotation_axis = Vector(1, 0, 0)

    #
    # Create the PolarizedPhotonBunch.
    #
    # To match the deviation sign conventions with those adopted in the crystal diffraction part,
    # I have to define a positive deviation as a clockwise rotation from the y axis,
    # and consequently a negative deviation as a counterclockwise rotation from the y axis.
    #
    polarized_photons = list()
    deviations = np.multiply(deviations, 1e-3)  # mrad --> rad

    for i in range(len(deviations)):
        stokes_vector = StokesVector([s_0[i], s_1[i], s_2[i], s_3[i]])
        direction = base_direction.rotateAroundAxis(rotation_axis,
                                                    deviations[i])
        incoming_photon = PolarizedPhoton(energy, direction, stokes_vector)
        polarized_photons.append(incoming_photon)

    photon_bunch = PolarizedPhotonBunch(polarized_photons)

    return photon_bunch
Exemple #10
0
def calculate_with_polarized_photon(method=0):

    # Create a diffraction setup.

    print("\nCreating a diffraction setup...")
    diffraction_setup = DiffractionSetup(
        geometry_type=BraggDiffraction(),  # GeometryType object
        crystal_name="Si",  # string
        thickness=1e-2,  # meters
        miller_h=1,  # int
        miller_k=1,  # int
        miller_l=1,  # int
        asymmetry_angle=
        0,  #10.0*numpy.pi/180.,                              # radians
        azimuthal_angle=0.0)  # radians                            # int

    energy = 8000.0  # eV
    angle_deviation_min = -100e-6  # radians
    angle_deviation_max = 100e-6  # radians
    angle_deviation_points = 500

    angle_step = (angle_deviation_max -
                  angle_deviation_min) / angle_deviation_points

    bunch_in = PolarizedPhotonBunch()

    bragg_angle = diffraction_setup.angleBragg(energy)

    print("Bragg angle for E=%f eV is %f deg" %
          (energy, bragg_angle * 180.0 / numpy.pi))

    # Create a Diffraction object.
    diffraction = Diffraction()

    #
    # get wavevector with incident direction matching Bragg angle
    #
    K0 = diffraction_setup.getK0(energy)
    K0unitary = K0.getNormalizedVector()

    print("K0", K0.components())

    # method = 0 # diffraction for individual photons
    # method = 1 # diffraction for bunch
    ZZ = numpy.zeros(angle_deviation_points)

    if method == 0:
        bunch_out = PolarizedPhotonBunch()

        for ia in range(angle_deviation_points):
            deviation = angle_deviation_min + ia * angle_step

            # angle =  deviation + bragg_angle
            # yy = numpy.cos(angle)
            # zz = - numpy.abs(numpy.sin(angle))
            # photon = PolarizedPhoton(energy_in_ev=energy,direction_vector=Vector(0.0,yy,zz),
            #                          stokes_vector=StokesVector([1,0,1,0]))

            # minus sign in angle is to perform cw rotation when deviation increses
            Vin = K0unitary.rotateAroundAxis(Vector(1, 0, 0), -deviation)
            photon = PolarizedPhoton(energy_in_ev=energy,
                                     direction_vector=Vin,
                                     stokes_vector=StokesVector([1, 0, 1, 0]))

            photon_out = diffraction.calculateDiffractedPolarizedPhoton(
                diffraction_setup,
                incoming_polarized_photon=photon,
                inclination_angle=0.0)
            bunch_out.addPhoton(photon_out)
            ZZ[ia] = angle_deviation_min + ia * angle_step

    elif method == 1:  # diffraction for bunch
        for ia in range(angle_deviation_points):
            deviation = angle_deviation_min + ia * angle_step

            # angle = deviation + bragg_angle
            # yy = numpy.cos(angle)
            # zz = - numpy.abs(numpy.sin(angle))
            # photon = PolarizedPhoton(energy_in_ev=energy,direction_vector=Vector(0.0,yy,zz),
            #                          stokes_vector=StokesVector([1,0,1,0]))

            # minus sign in angle is to perform cw rotation when deviation increses
            Vin = K0unitary.rotateAroundAxis(Vector(1, 0, 0), -deviation)
            photon = PolarizedPhoton(energy_in_ev=energy,
                                     direction_vector=Vin,
                                     stokes_vector=StokesVector([1, 0, 1, 0]))

            bunch_in.addPhoton(photon)
            ZZ[ia] = angle_deviation_min + ia * angle_step

        bunch_out = diffraction.calculateDiffractedPolarizedPhotonBunch(
            diffraction_setup, bunch_in, 0.0)

    bunch_out_dict = bunch_out.toDictionary()

    plot(1e6 * ZZ,
         bunch_out_dict["s0"],
         1e6 * ZZ,
         bunch_out_dict["s1"],
         legend=["S0", "S1"],
         xtitle="theta - thetaB [urad]",
         title="Polarized reflectivity calculation using method %d" % method)
    def generate(self):

        if self.ENERGY_POINTS == 1:
            # monochromatic bunch.
            self.ENERGY_MIN = self.ENERGY_MAX = self.ENERGY

        energies = np.linspace(self.ENERGY_MIN, self.ENERGY_MAX,
                               self.ENERGY_POINTS)

        if self.ANGLE_DEVIATION_POINTS == 1:
            # unidirectional bunch.
            ANGLE_DEVIATION_MIN = ANGLE_DEVIATION_MAX = self.ANGLE_DEVIATION * 1e-6  # urad

        else:
            ANGLE_DEVIATION_MIN = self.ANGLE_DEVIATION_MIN * 1e-6  # urad
            ANGLE_DEVIATION_MAX = self.ANGLE_DEVIATION_MAX * 1e-6  # urad

        deviations = np.linspace(ANGLE_DEVIATION_MIN, ANGLE_DEVIATION_MAX,
                                 self.ANGLE_DEVIATION_POINTS)

        stokes_vector = StokesVector(
            [self.STOKES_S0, self.STOKES_S1, self.STOKES_S2, self.STOKES_S3])

        # Following XOP conventions, the photon bunch travels along the y axis in the lab frame of reference.
        base_direction = Vector(0, 1, 0)
        # TODO: check this sign and possibly change it.
        # Setting (-1,0,0) means that negative deviation correspond to positive vz and after rotation
        # to match the crystal correspond to theta_bragg -  delta, so deviation has the same sign of delta

        rotation_axis = Vector(-1, 0, 0)

        # To match the deviation sign conventions with those adopted in the crystal diffraction part,
        # I have to define a positive deviation as a clockwise rotation from the y axis,
        # and consequently a negative deviation as a counterclockwise rotation from the y axis.

        polarized_photons = list()
        for energy in energies:
            for deviation in deviations:
                direction = base_direction.rotateAroundAxis(
                    rotation_axis, deviation)
                incoming_photon = PolarizedPhoton(energy, direction,
                                                  stokes_vector)
                polarized_photons.append(incoming_photon)

        photon_bunch = PolarizedPhotonBunch(polarized_photons)

        # Dump data to file if requested.
        if self.DUMP_TO_FILE:

            print("PhotonSource: Writing data in {file}...\n".format(
                file=self.FILE_NAME))

            with open(self.FILE_NAME, "w") as file:
                try:
                    file.write(
                        "#S 1 photon bunch\n"
                        "#N 9\n"
                        "#L  Energy [eV]  Vx  Vy  Vz  S0  S1  S2  S3  CircularPolarizationDregree\n"
                    )
                    file.write(photon_bunch.toString())
                    file.close()
                    print("File written to disk: %s \n" % self.FILE_NAME)
                except:
                    raise Exception(
                        "PhotonSource: The data could not be dumped onto the specified file!\n"
                    )

        self.send("photon bunch", photon_bunch)
        print("PhotonSource: Photon bunch generated.\n")
 def testEnergy(self):
     photon = PolarizedPhoton(4000, Vector(0, 0, 1),
                              StokesVector([1.0, 0.0, 1.0, 0.0]))
     self.assertEqual(photon.energy(), 4000)