Exemplo n.º 1
0
def example_branch_3(surface_shape_file, do_plot=True):
    #
    # source
    #
    # beam0 = Beam.initialize_as_pencil(N=500)
    source = SourceGaussian.initialize_from_keywords(
        number_of_rays=100000,
        sigmaX=0.0,
        sigmaY=0.0,
        sigmaZ=0.0,
        sigmaXprime=1e-4,
        sigmaZprime=1e-4,
    )
    beam0 = Beam()
    beam0.genSource(source)
    print(beam0.info())

    if do_plot:
        plotxy(beam0, 4, 6, title="Image 0", nbins=201)

    #
    # syned definitopns
    #

    # boundaries
    rlen1 = 0.6
    rlen2 = 0.6
    rwidx1 = 0.05
    rwidx2 = 0.05

    #
    # shadow definitions
    #
    mirror1 = S4SurfaceDataMirrorElement(optical_element=S4SurfaceDataMirror(
        name="M1",
        surface_data_file=surface_shape_file,
        boundary_shape=Rectangle(x_left=-rwidx2,
                                 x_right=rwidx1,
                                 y_bottom=-rlen2,
                                 y_top=rlen1)),
                                         coordinates=ElementCoordinates(
                                             p=100.0,
                                             q=1000.0,
                                             angle_radial=numpy.radians(88.8)))
    print(mirror1.info())

    #
    # run
    #
    beam1, mirr1 = mirror1.trace_beam(beam0)
    print(mirr1.info())

    #
    # check
    #

    if do_plot:
        plotxy(beam1, 1, 3, title="Image 1", nbins=101, nolost=1)
        plotxy(mirr1, 2, 1, title="Footprint 1", nbins=101, nolost=1)
Exemplo n.º 2
0
def example_branch_2(do_plot=True):
    source = SourceGaussian.initialize_from_keywords(
        number_of_rays=100000,
        sigmaX=0.0,
        sigmaY=0.0,
        sigmaZ=0.0,
        sigmaXprime=1e-6,
        sigmaZprime=1e-6,
    )
    beam0 = Beam()
    beam0.genSource(source)
    print(beam0.info())

    if do_plot:
        plotxy(beam0, 4, 6, title="Image 0", nbins=201)

    #
    # syned definitopns
    #

    # boundaries
    boundary_shape = None  #Rectangle(x_left=-rwidx2,x_right=rwidx1,y_bottom=-rlen2,y_top=rlen1)

    #
    # shadow definitions
    #
    mirror1 = S4ToroidalMirrorElement(optical_element=S4ToroidalMirror(
        name="M1",
        surface_calculation=SurfaceCalculation.EXTERNAL,
        min_radius=0.157068,
        maj_radius=358.124803 - 0.157068,
        boundary_shape=boundary_shape),
                                      coordinates=ElementCoordinates(
                                          p=10.0,
                                          q=6.0,
                                          angle_radial=numpy.radians(88.8)))

    print(mirror1.info())

    #
    # run
    #
    beam1, mirr1 = mirror1.trace_beam(beam0)
    print(mirr1.info())

    #
    # check
    #

    if do_plot:
        plotxy(beam1, 1, 3, title="Image 1", nbins=101, nolost=1)
        plotxy(mirr1, 2, 1, title="Footprint 1", nbins=101, nolost=1)
Exemplo n.º 3
0
        S4SurfaceDataMirrorElement

    from shadow4.syned.shape import Rectangle, Direction, Side  # TODO from syned.beamline.shape
    from srxraylib.plot.gol import set_qt

    set_qt()
    do_plot = True

    source = SourceGaussian.initialize_from_keywords(number_of_rays=10000,
                                                     sigmaX=0.0,
                                                     sigmaY=0.0,
                                                     sigmaZ=0.0,
                                                     sigmaXprime=1e-6,
                                                     sigmaZprime=1e-6, )
    beam0 = Beam()
    beam0.genSource(source)
    print(beam0.info())

    if do_plot:
        plotxy(beam0, 4, 6, title="Image 0", nbins=201)

    rlen1 = 0.6
    rlen2 = 0.6
    rwidx1 = 0.05
    rwidx2 = 0.05

    base_element = S4ToroidalMirror(name="M1b",
                                    surface_calculation=SurfaceCalculation.EXTERNAL,
                                    min_radius=0.157068,
                                    maj_radius=358.124803 - 0.157068,
                                    boundary_shape=Rectangle(x_left=-rwidx2, x_right=rwidx1, y_bottom=-rlen2,
Exemplo n.º 4
0
def example_branch_5(surface_type, do_plot=True):
    #
    # source
    #
    source = SourceGaussian.initialize_from_keywords(
        number_of_rays=100000,
        sigmaX=0.0,
        sigmaY=0.0,
        sigmaZ=0.0,
        sigmaXprime=1e-6,
        sigmaZprime=1e-6,
    )
    beam0 = Beam()
    beam0.genSource(source)
    # print(beam0.info())

    #
    # syned definitopns
    #
    # boundaries
    boundary_shape = None

    coordinates_syned = ElementCoordinates(p=10.0,
                                           q=10.0,
                                           angle_radial=numpy.radians(88.8))

    # surface shape

    if surface_type == "plane":
        mirror1 = S4PlaneMirrorElement(optical_element=S4PlaneMirror(
            name="M1", boundary_shape=boundary_shape),
                                       coordinates=coordinates_syned)
    elif surface_type == "sphere":
        mirror1 = S4SphereMirrorElement(optical_element=S4SphereMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=False,
            surface_calculation=SurfaceCalculation.INTERNAL,
            p_focus=10.0,
            q_focus=10.0,
            grazing_angle=numpy.radians(90.0 - 88.8)),
                                        coordinates=coordinates_syned)
    elif surface_type == "spherical_cylinder_tangential":
        mirror1 = S4SphereMirrorElement(optical_element=S4SphereMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=True,
            cylinder_direction=Direction.TANGENTIAL,
            surface_calculation=SurfaceCalculation.INTERNAL,
            p_focus=10.0,
            q_focus=10.0,
            grazing_angle=numpy.radians(90.0 - 88.8)),
                                        coordinates=coordinates_syned)
    elif surface_type == "spherical_cylinder_sagittal":
        mirror1 = S4SphereMirrorElement(optical_element=S4SphereMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=True,
            cylinder_direction=Direction.SAGITTAL,
            surface_calculation=SurfaceCalculation.INTERNAL,
            p_focus=10.0,
            q_focus=10.0,
            grazing_angle=numpy.radians(90.0 - 88.8)),
                                        coordinates=coordinates_syned)
    elif surface_type == "ellipsoid":
        mirror1 = S4EllipsoidMirrorElement(optical_element=S4EllipsoidMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=False,
            surface_calculation=SurfaceCalculation.INTERNAL,
            p_focus=20.0,
            q_focus=10.0,
            grazing_angle=0.003),
                                           coordinates=coordinates_syned)
    elif surface_type == "elliptical_cylinder":
        mirror1 = S4EllipsoidMirrorElement(optical_element=S4EllipsoidMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=True,
            cylinder_direction=Direction.TANGENTIAL,
            surface_calculation=SurfaceCalculation.INTERNAL,
            p_focus=20.0,
            q_focus=10.0,
            grazing_angle=0.003),
                                           coordinates=coordinates_syned)
    elif surface_type == "hyperboloid":
        mirror1 = S4HyperboloidMirrorElement(
            optical_element=S4HyperboloidMirror(
                name="M1",
                boundary_shape=boundary_shape,
                is_cylinder=False,
                surface_calculation=SurfaceCalculation.INTERNAL,
                p_focus=20.0,
                q_focus=10.0,
                grazing_angle=0.003),
            coordinates=coordinates_syned)
    elif surface_type == "hyperbolic_cylinder":
        mirror1 = S4HyperboloidMirrorElement(
            optical_element=S4HyperboloidMirror(
                name="M1",
                boundary_shape=boundary_shape,
                is_cylinder=True,
                cylinder_direction=Direction.TANGENTIAL,
                surface_calculation=SurfaceCalculation.INTERNAL,
                p_focus=20.0,
                q_focus=10.0,
                grazing_angle=0.003),
            coordinates=coordinates_syned)
    elif surface_type == "paraboloid":
        mirror1 = S4ParaboloidMirrorElement(optical_element=S4ParaboloidMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=False,
            surface_calculation=SurfaceCalculation.INTERNAL,
            at_infinity=Side.SOURCE,
            p_focus=20.0,
            q_focus=10.0,
            grazing_angle=0.003),
                                            coordinates=coordinates_syned)
    elif surface_type == "parabolic_cylinder":
        mirror1 = S4ParaboloidMirrorElement(optical_element=S4ParaboloidMirror(
            name="M1",
            boundary_shape=boundary_shape,
            is_cylinder=True,
            cylinder_direction=Direction.TANGENTIAL,
            surface_calculation=SurfaceCalculation.INTERNAL,
            at_infinity=Side.SOURCE,
            p_focus=20.0,
            q_focus=10.0,
            grazing_angle=0.003),
                                            coordinates=coordinates_syned)
    elif surface_type == "conic":
        mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
            name="M1",
            boundary_shape=boundary_shape,
            conic_coefficients=[
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0
            ]),
                                       coordinates=coordinates_syned)
    else:
        raise Exception("undefined surface shape")

    #
    # run
    #
    print(mirror1.info())
    beam1, mirr1 = mirror1.trace_beam(beam0)

    #
    # check
    #

    if do_plot:
        plotxy(beam1, 1, 3, nbins=101, nolost=1, title=surface_type)
Exemplo n.º 5
0
def example_branch_1(do_plot=True):
    #
    # source
    #
    source = SourceGaussian.initialize_from_keywords(
        number_of_rays=100000,
        sigmaX=0.0,
        sigmaY=0.0,
        sigmaZ=0.0,
        sigmaXprime=1e-6,
        sigmaZprime=1e-6,
    )
    beam0 = Beam()
    beam0.genSource(source)
    print(beam0.info())

    if do_plot:
        plotxy(beam0, 4, 6, title="Image 0", nbins=201)

    #
    # syned definitopns
    #

    # surface shape

    # boundaries
    # boundary_shape = None
    rlen1 = 5e-05
    rlen2 = 5e-05
    rwidx1 = 2e-05
    rwidx2 = 2e-05
    boundary_shape = Rectangle(x_left=-rwidx2,
                               x_right=rwidx1,
                               y_bottom=-rlen2,
                               y_top=rlen1)
    # boundary_shape = Rectangle(x_left=-1e-05, x_right=2e-05, y_bottom=-5e-04, y_top=7e-04)
    # boundary_shape = Ellipse(a_axis_min=-rwidx2/2, a_axis_max=rwidx2/2, b_axis_min=-rlen2/2, b_axis_max=rlen2/2)
    # boundary_shape = Ellipse(a_axis_min=-0e-05, a_axis_max=1e-05, b_axis_min=-1.5e-05, b_axis_max=2.5e-05)
    # boundary_shape = Ellipse(a_axis_min=0, a_axis_max=1e-05, b_axis_min=-0.0005, b_axis_max=0)

    # rlen1 = -2.5e-05
    # rlen2 = 5e-05
    # rwidx1 = 1e-05
    # rwidx2 = 2e-05
    #
    # boundary_shape = TwoEllipses(
    #     a1_axis_min=-rwidx1 / 2, a1_axis_max=rwidx1 / 2, b1_axis_min=-rlen1 / 2, b1_axis_max=rlen1 / 2,
    #     a2_axis_min=-rwidx2 / 2, a2_axis_max=rwidx2 / 2, b2_axis_min=-rlen2 / 2, b2_axis_max=rlen2 / 2)

    coordinates_syned = ElementCoordinates(p=10.0,
                                           q=6.0,
                                           angle_radial=numpy.radians(88.8))

    #
    # shadow definitions
    #
    mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
        name="M1",
        conic_coefficients=[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0],
        boundary_shape=boundary_shape),
                                   coordinates=coordinates_syned)

    print(mirror1.info())

    #
    # run
    #
    beam1, mirr1 = mirror1.trace_beam(beam_in=beam0)
    print(mirr1.info())

    #
    # check
    #

    if do_plot:
        plotxy(beam1, 1, 3, title="Image 1", nbins=101, nolost=1)
        plotxy(mirr1, 2, 1, title="Footprint 1", nbins=101, nolost=1)

    #
    # M2
    #

    mirror2 = S4ConicMirrorElement(optical_element=S4ConicMirror(
        conic_coefficients=[0, 0, 0, 0, 0, 0, 0, 0, -1, 0],
        boundary_shape=Rectangle(-100e-6, 100e-6, -150e-6, 150e-6)),
                                   coordinates=ElementCoordinates(
                                       p=10.0,
                                       q=100.0,
                                       angle_radial=(0.5 * numpy.pi - 0.003)))

    print(mirror2.info())
    #
    #
    if do_plot:
        beam2, mirr2 = mirror2.trace_beam(beam1)
        plotxy(beam2, 1, 3, title="Image 2", nbins=101, nolost=1)
        plotxy(mirr2, 2, 1, title="Footprint 2", nbins=101, nolost=1)
Exemplo n.º 6
0
def example_branch_4(do_plot=True, f_refl=0):

    #
    # source
    #
    # beam0 = Beam.initialize_as_pencil(N=500)
    source = SourceGaussian.initialize_from_keywords(
        number_of_rays=100000,
        sigmaX=0.0,
        sigmaY=0.0,
        sigmaZ=0.0,
        sigmaXprime=1e-6,
        sigmaZprime=1e-6,
    )
    beam0 = Beam()
    numpy.random.seed(123456)
    beam0.genSource(source)
    beam0.set_photon_wavelength(5e-10)
    print(beam0.info())

    if do_plot:
        plotxy(beam0, 4, 6, title="Image 0", nbins=201)

    #
    # syned definitopns
    #

    # surface shape
    # boundaries
    rlen1 = 5e-05
    rlen2 = 5e-05
    rwidx1 = 2e-05
    rwidx2 = 2e-05

    boundary_shape = Rectangle(x_left=-rwidx2,
                               x_right=rwidx1,
                               y_bottom=-rlen2,
                               y_top=rlen1)

    coordinates_syned = ElementCoordinates(p=10.0,
                                           q=6.0,
                                           angle_radial=numpy.radians(88.8))

    #
    # shadow definitions
    #
    if f_refl == 0:  # prerefl

        PreRefl.prerefl(interactive=False,
                        SYMBOL="SiC",
                        DENSITY=3.217,
                        FILE="SiC.dat",
                        E_MIN=100.0,
                        E_MAX=20000.0,
                        E_STEP=100.0)
        mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
            name="M1",
            conic_coefficients=[
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0
            ],
            boundary_shape=boundary_shape,
            f_reflec=1,
            f_refl=f_refl,
            file_refl="SiC.dat"),
                                       coordinates=coordinates_syned)
    elif f_refl == 1:  # refraction index
        import xraylib
        refraction_index = xraylib.Refractive_Index("SiC", 2.4797, 3.217)
        mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
            name="M1",
            conic_coefficients=[
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0
            ],
            boundary_shape=boundary_shape,
            f_reflec=1,
            f_refl=f_refl,
            file_refl="",
            refraction_index=refraction_index),
                                       coordinates=coordinates_syned)
    elif f_refl == 2:  # user file: 1D  vs angle
        mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
            name="M1",
            conic_coefficients=[
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0
            ],
            boundary_shape=boundary_shape,
            f_reflec=1,
            f_refl=f_refl,
            file_refl="../../oasys_workspaces/xoppy_f1f2_139980555361648.dat"),
                                       coordinates=coordinates_syned)
    elif f_refl == 3:  # user file 1D vs energy
        mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
            name="M1",
            conic_coefficients=[
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0
            ],
            boundary_shape=boundary_shape,
            f_reflec=1,
            f_refl=f_refl,
            file_refl="../../oasys_workspaces/xoppy_f1f2_139981943656272.dat"),
                                       coordinates=coordinates_syned)
    elif f_refl == 4:  # user file
        mirror1 = S4ConicMirrorElement(optical_element=S4ConicMirror(
            name="M1",
            conic_coefficients=[
                0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0
            ],
            boundary_shape=boundary_shape,
            f_reflec=1,
            f_refl=f_refl,
            file_refl="../../oasys_workspaces/xoppy_f1f2_139980938100080.dat"),
                                       coordinates=coordinates_syned)

    print(mirror1.info())

    #
    # run
    #
    beam1, mirr1 = mirror1.trace_beam(beam0)
    print(mirr1.info())

    #
    # check
    #

    if do_plot:
        plotxy(beam1, 1, 3, title="Image 1", nbins=101, nolost=1)
        plotxy(mirr1, 2, 1, title="Footprint 1", nbins=101, nolost=1)
Exemplo n.º 7
0
    #
    # source
    #
    src = SourceGaussian.initialize_from_keywords(
        number_of_rays=10000,
        sigmaX=1.0e-6,
        sigmaY=0.0,
        sigmaZ=1.0e-6,
        sigmaXprime=0.0002,
        sigmaZprime=0.0002,
        real_space_center=[0.0, 0.0, 0.0],
        direction_space_center=[0.0, 0.0])
    beam = Beam()

    beam.genSource(src)
    beam.set_photon_energy_eV(1000.0)

    print(beam.info())

    # plotxy(Beam3.initialize_from_shadow4_beam(beam),1,3,nbins=100,title="SOURCE")

    #
    # grating
    #
    g = S4PlaneGrating(
        name="my_grating",
        boundary_shape=None,  # BoundaryShape(),
        ruling=600000.0,
        ruling_coeff_linear=260818.35944225,
        ruling_coeff_quadratic=260818.35944225,
Exemplo n.º 8
0
class ShadowBeam:
    class ScanningData(object):
        def __init__(self,
                     scanned_variable_name,
                     scanned_variable_value,
                     scanned_variable_display_name,
                     scanned_variable_um,
                     additional_parameters={}):
            self.__scanned_variable_name = scanned_variable_name
            self.__scanned_variable_value = scanned_variable_value
            self.__scanned_variable_display_name = scanned_variable_display_name
            self.__scanned_variable_um = scanned_variable_um

            self.__additional_parameters = additional_parameters

        def get_scanned_variable_name(self):
            return self.__scanned_variable_name

        def get_scanned_variable_value(self):
            return self.__scanned_variable_value

        def get_scanned_variable_display_name(self):
            return self.__scanned_variable_display_name

        def get_scanned_variable_um(self):
            return self.__scanned_variable_um

        def has_additional_parameter(self, name):
            return name in self.__additional_parameters.keys()

        def get_additional_parameter(self, name):
            return self.__additional_parameters[name]

    def __new__(cls, oe_number=0, beam=None, number_of_rays=0):
        self = super().__new__(cls)
        self._oe_number = oe_number
        if (beam is None):
            if number_of_rays > 0:
                self._beam = Beam(number_of_rays)
            else:
                self._beam = Beam()
        else:
            self._beam = beam

        self.history = []
        self.scanned_variable_data = None

        return self

    def get_number_of_rays(self):
        return self._beam.rays.shape[0]

    def setBeam(self, beam):
        self._beam = beam

    def setScanningData(self,
                        scanned_variable_data=ScanningData(
                            None, None, None, None)):
        self.scanned_variable_data = scanned_variable_data

    def loadFromFile(self, file_name):
        if not self._beam is None:
            if os.path.exists(file_name):
                self._beam.load(file_name)
            else:
                raise Exception("File " + file_name + " not existing")

    def writeToFile(self, file_name):
        if not self._beam is None:
            self._beam.write(file_name)

    def duplicate(self, copy_rays=True, history=True):
        beam = Beam()
        if copy_rays: beam.rays = copy.deepcopy(self._beam.rays)

        new_shadow_beam = ShadowBeam(self._oe_number, beam)
        new_shadow_beam.setScanningData(self.scanned_variable_data)

        if history:
            for historyItem in self.history:
                new_shadow_beam.history.append(historyItem)

        return new_shadow_beam

    @classmethod
    def mergeBeams(cls, beam_1, beam_2):
        if beam_1 and beam_2:
            rays_1 = None
            rays_2 = None

            if len(getattr(beam_1._beam, "rays", numpy.zeros(0))) > 0:
                rays_1 = copy.deepcopy(beam_1._beam.rays)
            if len(getattr(beam_2._beam, "rays", numpy.zeros(0))) > 0:
                rays_2 = copy.deepcopy(beam_2._beam.rays)

            merged_beam = beam_1.duplicate(copy_rays=False, history=True)

            if not rays_1 is None and not rays_2 is None:
                merged_beam._oe_number = beam_1._oe_number
                merged_beam._beam.rays = numpy.append(rays_1, rays_2, axis=0)
            elif not rays_1 is None:
                merged_beam._beam.rays = rays_1
                merged_beam._oe_number = beam_1._oe_number
            elif not rays_2 is None:
                merged_beam._beam.rays = rays_2
                merged_beam._oe_number = beam_2._oe_number

            merged_beam._beam.rays[:, 11] = numpy.arange(
                1,
                len(merged_beam._beam.rays) + 1, 1)  # ray_index

            return merged_beam

    @classmethod
    def traceFromSource(cls,
                        shadow_src,
                        write_begin_file=0,
                        write_start_file=0,
                        write_end_file=0,
                        history=True,
                        widget_class_name=None):
        self = cls.__new__(ShadowBeam, beam=Beam())

        shadow_src.self_repair()

        shadow_source_start = shadow_src.duplicate()

        if write_start_file == 1:
            shadow_src.src.write("start.00")

        self._beam.genSource(shadow_src.src)

        shadow_src.self_repair()

        if write_begin_file:
            self.writeToFile("begin.dat")

        if write_end_file == 1:
            shadow_src.src.write("end.00")

        shadow_source_end = shadow_src.duplicate()

        if history:
            self.history.append(
                ShadowOEHistoryItem(shadow_source_start=shadow_source_start,
                                    shadow_source_end=shadow_source_end,
                                    widget_class_name=widget_class_name))

        return self

    @classmethod
    def traceFromOE(cls,
                    input_beam,
                    shadow_oe,
                    write_start_file=0,
                    write_end_file=0,
                    history=True,
                    widget_class_name=None):

        self = cls.initializeFromPreviousBeam(input_beam)

        shadow_oe.self_repair()

        if history:
            history_shadow_oe_start = shadow_oe.duplicate()

        if write_start_file == 1:
            shadow_oe._oe.write("start.%02d" % self._oe_number)

        self._beam.traceOE(shadow_oe._oe, self._oe_number)

        shadow_oe.self_repair()

        if write_end_file == 1:
            shadow_oe._oe.write("end.%02d" % self._oe_number)

        if history:
            history_shadow_oe_end = shadow_oe.duplicate()

            #N.B. history[0] = Source
            if not self._oe_number == 0:
                if len(self.history) - 1 < self._oe_number:
                    self.history.append(
                        ShadowOEHistoryItem(
                            oe_number=self._oe_number,
                            input_beam=input_beam.duplicate(),
                            shadow_oe_start=history_shadow_oe_start,
                            shadow_oe_end=history_shadow_oe_end,
                            widget_class_name=widget_class_name))
                else:
                    self.history[self._oe_number] = ShadowOEHistoryItem(
                        oe_number=self._oe_number,
                        input_beam=input_beam.duplicate(),
                        shadow_oe_start=history_shadow_oe_start,
                        shadow_oe_end=history_shadow_oe_end,
                        widget_class_name=widget_class_name)

        return self

    @classmethod
    def traceIdealLensOE(cls,
                         input_beam,
                         shadow_oe,
                         history=True,
                         widget_class_name=None):

        self = cls.initializeFromPreviousBeam(input_beam)

        shadow_oe.self_repair()

        if history:
            history_shadow_oe_start = shadow_oe.duplicate()

        self._beam.traceIdealLensOE(shadow_oe._oe, self._oe_number)

        shadow_oe.self_repair()

        if history:
            history_shadow_oe_end = shadow_oe.duplicate()

            #N.B. history[0] = Source
            if not self._oe_number == 0:
                if len(self.history) - 1 < self._oe_number:
                    self.history.append(
                        ShadowOEHistoryItem(
                            oe_number=self._oe_number,
                            input_beam=input_beam.duplicate(),
                            shadow_oe_start=history_shadow_oe_start,
                            shadow_oe_end=history_shadow_oe_end,
                            widget_class_name=widget_class_name))
                else:
                    self.history[self._oe_number] = ShadowOEHistoryItem(
                        oe_number=self._oe_number,
                        input_beam=input_beam.duplicate(),
                        shadow_oe_start=history_shadow_oe_start,
                        shadow_oe_end=history_shadow_oe_end,
                        widget_class_name=widget_class_name)

        return self

    @classmethod
    def traceFromCompoundOE(cls,
                            input_beam,
                            shadow_oe,
                            write_start_files=0,
                            write_end_files=0,
                            write_star_files=0,
                            write_mirr_files=0,
                            history=True,
                            widget_class_name=None):
        self = cls.initializeFromPreviousBeam(input_beam)

        shadow_oe.self_repair()

        if history:
            history_shadow_oe_start = shadow_oe.duplicate()

        self._beam.traceCompoundOE(shadow_oe._oe,
                                   from_oe=self._oe_number,
                                   write_start_files=write_start_files,
                                   write_end_files=write_end_files,
                                   write_star_files=write_star_files,
                                   write_mirr_files=write_mirr_files)

        shadow_oe.self_repair()

        if history:
            history_shadow_oe_end = shadow_oe.duplicate()

            # N.B. history[0] = Source
            if not self._oe_number == 0:
                if len(self.history) - 1 < self._oe_number:
                    self.history.append(
                        ShadowOEHistoryItem(
                            oe_number=self._oe_number,
                            input_beam=input_beam.duplicate(),
                            shadow_oe_start=history_shadow_oe_start,
                            shadow_oe_end=history_shadow_oe_end,
                            widget_class_name=widget_class_name))
                else:
                    self.history[self._oe_number] = ShadowOEHistoryItem(
                        oe_number=self._oe_number,
                        input_beam=input_beam.duplicate(),
                        shadow_oe_start=history_shadow_oe_start,
                        shadow_oe_end=history_shadow_oe_end,
                        widget_class_name=widget_class_name)

        return self

    @classmethod
    def initializeFromPreviousBeam(cls, input_beam):
        self = input_beam.duplicate()
        self._oe_number = input_beam._oe_number + 1

        return self

    def getOEHistory(self, oe_number=None):
        if oe_number is None:
            return self.history
        else:
            return self.history[oe_number]

    def historySize(self):
        return len(self.history)