def _validate_sample_inclusion(self, sample, options, erracc): self._validate_sample(sample, options, erracc) # Substrate material substrate_material = apply_lazy(sample.substrate_material, sample, options) if substrate_material is VACUUM: exc = ValueError("Substrate material cannot be VACUUM.") erracc.add_exception(exc) self._validate_material(substrate_material, options, erracc) # Inclusion material inclusion_material = apply_lazy(sample.inclusion_material, sample, options) if inclusion_material is VACUUM: exc = ValueError("Substrate material cannot be VACUUM.") erracc.add_exception(exc) self._validate_material(inclusion_material, options, erracc) # Inclusion diameter inclusion_diameter_m = apply_lazy(sample.inclusion_diameter_m, sample, options) if inclusion_diameter_m <= 0: exc = ValueError( "Diameter ({0:g} m) must be greater than 0.".format( inclusion_diameter_m)) erracc.add_exception(exc)
def _export_sample_horizontallayers(self, sample, options, erracc, simdata, simops): self._validate_sample_horizontallayers(sample, options, erracc) regionops = simdata.getRegionOptions() layers = apply_lazy(sample.layers, sample, options) zpositions_m = sample.layers_zpositions_m for i, (layer, zposition_m) in enumerate(zip(layers, zpositions_m)): region = regionops.getRegion(i) self._export_material(layer.material, options, erracc, region) zmin_m, zmax_m = zposition_m parameters = [abs(zmax_m) * 1e9, abs(zmin_m) * 1e9, 0.0, 0.0] region.setParameters(parameters) if sample.has_substrate(): substrate_material = apply_lazy(sample.substrate_material, sample, options) region = regionops.getRegion(regionops.getNumberRegions() - 1) self._export_material(substrate_material, options, erracc, region) zmin_m, _zmax_m = zpositions_m[-1] parameters = region.getParameters() parameters[0] = abs(zmin_m) * 1e9 parameters[2] = parameters[0] + 10.0 region.setParameters(parameters) else: zmin_m, _zmax_m = zpositions_m[-1] simops.setTotalThickness_nm(abs(zmin_m) * 1e9)
def _validate_sample_verticallayers(self, sample, options, erracc): self._validate_sample(sample, options, erracc) # Left material left_material = apply_lazy(sample.left_material, sample, options) if left_material is VACUUM: exc = ValueError("Left material cannot be VACUUM.") erracc.add_exception(exc) self._validate_material(left_material, options, erracc) # Layers layers = apply_lazy(sample.layers, sample, options) for layer in layers: self._validate_layer(layer, options, erracc) # Right material right_material = apply_lazy(sample.right_material, sample, options) if right_material is VACUUM: exc = ValueError("Right material cannot be VACUUM.") erracc.add_exception(exc) self._validate_material(right_material, options, erracc)
def apply(self, parent_option, options): xrayline = base.apply_lazy(self.xrayline, self, options) c1 = base.apply_lazy(self.c1, self, options) c2 = base.apply_lazy(self.c2, self, options) beam_energy_eV = base.apply_lazy(options.beam.energy_eV, options.beam, options) beam_particle = base.apply_lazy(options.beam.particle, options.beam, options) xrayline_energy_eV = max(xrayline.energy_eV - 100, 0.0) if beam_particle == Particle.ELECTRON: eabs_electron_eV = eabs_photon_eV = xrayline_energy_eV eabs_positron_eV = beam_energy_eV elif beam_particle == Particle.PHOTON: eabs_electron_eV = eabs_photon_eV = eabs_positron_eV = xrayline_energy_eV elif beam_particle == Particle.POSITRON: eabs_electron_eV = beam_energy_eV eabs_photon_eV = eabs_positron_eV = xrayline_energy_eV else: eabs_electron_eV = eabs_photon_eV = eabs_positron_eV = beam_energy_eV return SimulationParameters( eabs_electron_eV=eabs_electron_eV, eabs_photon_eV=eabs_photon_eV, eabs_positron_eV=eabs_positron_eV, c1=c1, c2=c2, wcc_eV=xrayline_energy_eV, wcr_eV=xrayline_energy_eV, )
def _export_detector_photon(self, detector, options, erracc, simdata, simops): self._validate_detector_photon(detector, options, erracc) elevation_deg = apply_lazy(detector.elevation_deg, detector, options) simops.TOA = elevation_deg azimuth_deg = apply_lazy(detector.azimuth_deg, detector, options) simops.PhieRX = azimuth_deg simops.FEmissionRX = 1 # Simulate x-rays
def test_lazymaterial(material, lazy_material): assert lazy_material == lazy_material assert material != lazy_material density_kg_per_m3 = base.apply_lazy(lazy_material.density_kg_per_m3, lazy_material, None) assert density_kg_per_m3 == pytest.approx(8960.0, abs=1e-4) density_g_per_cm3 = base.apply_lazy(lazy_material.density_g_per_cm3, lazy_material, None) assert density_g_per_cm3 == pytest.approx(8.9600, abs=1e-4)
def _validate_sample(self, sample, options, erracc): super()._validate_sample(sample, options, erracc) tilt_rad = apply_lazy(sample.tilt_rad, sample, options) if tilt_rad != 0.0: exc = ValueError("Sample tilt is not supported.") erracc.add_exception(exc) azimuth_rad = apply_lazy(sample.azimuth_rad, sample, options) if azimuth_rad != 0.0: exc = ValueError("Sample azimuth is not supported.") erracc.add_exception(exc)
def _export_beam_pencil(self, beam, options, erracc, simdata, simops): self._validate_beam_pencil(beam, options, erracc) # Energy energy_eV = apply_lazy(beam.energy_eV, beam, options) simops.setIncidentEnergy_keV(energy_eV / 1000.0) # keV # Position x0_m = apply_lazy(beam.x0_m, beam, options) simops.setPosition(x0_m * 1e9) # nm # Diameter simops.Beam_Diameter = 0.0 simops.Beam_angle = 0.0
def _validate_material(self, material, options, erracc): if material is VACUUM: return # Name name = apply_lazy(material.name, material, options).strip() if not name: exc = ValueError( "Name ({0:s}) must be at least one character.".format(name)) erracc.add_exception(exc) # Composition composition = apply_lazy(material.composition, material, options) for z, wf in composition.items(): try: pyxray.descriptor.Element(z) except (ValueError, TypeError) as exc: erracc.add_exception(exc) if wf <= 0.0 or wf > 1.0: exc = ValueError( "Weight fraction ({0:g}) must be between ]0.0, 1.0]") erracc.add_exception(exc) total = sum(composition.values()) if not math.isclose( total, 1.0, abs_tol=Material.WEIGHT_FRACTION_TOLERANCE): exc = ValueError( "Total weight fraction ({0:g}) does not equal 1.0.".format( total)) erracc.add_exception(exc) # Density density_kg_per_m3 = apply_lazy(material.density_kg_per_m3, material, options) if density_kg_per_m3 <= 0: exc = ValueError( "Density ({0:g}kg/m3) must be greater or equal to 0.".format( density_kg_per_m3)) erracc.add_exception(exc) # Color color = apply_lazy(material.color, material, options) if not matplotlib.colors.is_color_like(color): exc = ValueError("Color ({}) is not a valid color.".format(color)) erracc.add_exception(exc)
def apply(self, parent_option, options): # Check that x-ray line exists in material xrayline = self.xrayline if ( hasattr(xrayline, "atomic_number") and xrayline.atomic_number not in options.sample.atomic_numbers ): minimum_energy_eV = xrayline.energy_eV or 100.0 xrayline = LazyLowestEnergyXrayLine(minimum_energy_eV) xrayline = base.apply_lazy(xrayline, self, options) photon_detector = self._find_detector(options) relative_uncertainty = base.apply_lazy(self.relative_uncertainty, self, options) return ReferenceLine(xrayline, photon_detector, relative_uncertainty)
def _validate_layer(self, layer, options, erracc): # Material material = apply_lazy(layer.material, layer, options) self._validate_material(material, options, erracc) # Thickness thickness_m = apply_lazy(layer.thickness_m, layer, options) if thickness_m <= 0: exc = ValueError( "Thickness ({0:g} m) must be greater than 0.".format( thickness_m)) erracc.add_exception(exc)
def _export_material(self, material, options, erracc, index): self._validate_material(material, options, erracc) name = apply_lazy(material.name, material, options) filename = "mat{:02d}.mat".format(index) composition = apply_lazy(material.composition, material, options) density_g_per_cm3 = apply_lazy(material.density_g_per_cm3, material, options) penmaterial = PenelopeMaterial(name, composition, density_g_per_cm3, filename=filename) return penmaterial
def _validate_sample_horizontallayers(self, sample, options, erracc): self._validate_sample(sample, options, erracc) # Layers layers = apply_lazy(sample.layers, sample, options) for layer in layers: self._validate_layer(layer, options, erracc) # Substrate material substrate_material = apply_lazy(sample.substrate_material, sample, options) self._validate_material(substrate_material, options, erracc)
def _validate_sample(self, sample, options, erracc): # Tilt tilt_rad = apply_lazy(sample.tilt_rad, sample, options) if not math.isfinite(tilt_rad): exc = ValueError("Sample tilt must be a finite number.") erracc.add_exception(exc) # Azimuth azimuth_rad = apply_lazy(sample.azimuth_rad, sample, options) if not math.isfinite(azimuth_rad): exc = ValueError("Sample azimuth must be a finite number.") erracc.add_exception(exc)
def _validate_beam_pencil(self, beam, options, erracc): self._validate_beam(beam, options, erracc) # Position x0_m = apply_lazy(beam.x0_m, beam, options) if not math.isfinite(x0_m): exc = ValueError("Initial x position must be a finite number.") erracc.add_exception(exc) y0_m = apply_lazy(beam.y0_m, beam, options) if not math.isfinite(y0_m): exc = ValueError("Initial y position must be a finite number.") erracc.add_exception(exc)
def _validate_beam(self, beam, options, erracc): # Energy energy_eV = apply_lazy(beam.energy_eV, beam, options) if energy_eV <= 0.0: exc = ValueError( "Energy ({0:g} eV) must be greater than 0.0.".format( energy_eV)) erracc.add_exception(exc) # Particle particle = apply_lazy(beam.particle, beam, options) if not isinstance(particle, Particle): exc = ValueError("Unknown particle: {0}.".format(particle)) erracc.add_exception(exc)
def _export_sample_inclusion(self, sample, options, erracc, geometry, dsmaxs): self._validate_sample_inclusion(sample, options, erracc) # Surface inclusion_diameter_m = apply_lazy(sample.inclusion_diameter_m, sample, options) surface_cylinder = cylinder(100.0) # 100 cm radius surface_top = zplane(0.0) # z = 0 surface_bottom = zplane(-100.0) # z = -100 cm surface_sphere = sphere(inclusion_diameter_m / 2.0 * 100.0) # Inclusion module inclusion_material = apply_lazy(sample.inclusion_material, sample, options) penmaterial = self._export_material(inclusion_material, options, erracc, index=1) module_inclusion = Module(penmaterial, "Inclusion") module_inclusion.add_surface(surface_top, SidePointer.NEGATIVE) module_inclusion.add_surface(surface_sphere, SidePointer.NEGATIVE) dsmaxs[module_inclusion] = inclusion_diameter_m # Substrate module substrate_material = apply_lazy(sample.substrate_material, sample, options) penmaterial = self._export_material(substrate_material, options, erracc, index=2) module_substrate = Module(penmaterial, "Substrate") module_substrate.add_surface(surface_cylinder, SidePointer.NEGATIVE) module_substrate.add_surface(surface_top, SidePointer.NEGATIVE) module_substrate.add_surface(surface_bottom, SidePointer.POSITIVE) module_substrate.add_module(module_inclusion) # Geometry geometry.title = "Inclusion" geometry.add_module(module_substrate) geometry.add_module(module_inclusion) geometry.tilt_rad = apply_lazy(sample.tilt_rad, sample, options) geometry.rotation_rad = apply_lazy(sample.azimuth_rad, sample, options)
def _export_material(self, material, options, erracc, region): region.removeAllElements() composition = apply_lazy(material.composition, material, options) for z, fraction in composition.items(): region.addElement(pyxray.element_symbol(z), weight_fraction=fraction) region.update() # Calculate number of elements, mean atomic number region.User_Density = True density_g_per_cm3 = apply_lazy(material.density_g_per_cm3, material, options) region.Rho = density_g_per_cm3 name = apply_lazy(material.name, material, options).strip() region.Name = name
def _export_beam_pencil(self, beam, options, erracc, input): self._validate_beam_pencil(beam, options, erracc) particle = apply_lazy(beam.particle, beam, options) input.SKPAR.set(PARTICLE_INDEX[particle]) energy_eV = apply_lazy(beam.energy_eV, beam, options) input.SENERG.set(energy_eV) x0_m = apply_lazy(beam.x0_m, beam, options) y0_m = apply_lazy(beam.y0_m, beam, options) input.SPOSIT.set(x0_m * 1e2, y0_m * 1e2, 1.0) # cm input.SRADI.set(0.0) # cm input.SDIREC.set(180.0, 0.0) # pointing downwards input.SAPERT.set(0.0)
def _export_sample_substrate(self, sample, options, erracc, simdata, simops): self._validate_sample_substrate(sample, options, erracc) regionops = simdata.getRegionOptions() region = regionops.getRegion(0) material = apply_lazy(sample.material, sample, options) self._export_material(material, options, erracc, region)
def _validate_detector(self, detector, options, erracc): # Name name = apply_lazy(detector.name, detector, options).strip() if not name: exc = ValueError( "Detector name ({0:s}) must be at least one character.".format( name)) erracc.add_exception(exc)
def _validate_beam_pencil(self, beam, options, erracc): super()._validate_beam_pencil(beam, options, erracc) # Position y0_m = apply_lazy(beam.y0_m, beam, options) if y0_m != 0.0: exc = ValueError("Beam initial y position ({0:g}) must be 0.0".format(y0_m)) erracc.add_exception(exc)
def _validate_detector_photon(self, detector, options, erracc): self._validate_detector(detector, options, erracc) # Elevation elevation_rad = apply_lazy(detector.elevation_rad, detector, options) if elevation_rad < -math.pi / 2 or elevation_rad > math.pi / 2: exc = ValueError( "Elevation ({0:g} rad) must be between [-pi/2,pi/2].".format( elevation_rad)) erracc.add_exception(exc) # Azimuth azimuth_rad = apply_lazy(detector.azimuth_rad, detector, options) if azimuth_rad < 0 or azimuth_rad >= 2 * math.pi: exc = ValueError( "Azimuth ({0:g} rad) must be between [0, 2pi[.".format( azimuth_rad)) erracc.add_exception(exc)
def _validate_sample_sphere(self, sample, options, erracc): self._validate_sample(sample, options, erracc) # Material material = apply_lazy(sample.material, sample, options) if material is VACUUM: exc = ValueError("Material cannot be VACUUM.") erracc.add_exception(exc) self._validate_material(material, options, erracc) # Diameter diameter_m = apply_lazy(sample.diameter_m, sample, options) if diameter_m <= 0: exc = ValueError( "Diameter ({0:g} m) must be greater than 0.".format( diameter_m)) erracc.add_exception(exc)
def _validate_sample_substrate(self, sample, options, erracc): self._validate_sample(sample, options, erracc) # Material material = apply_lazy(sample.material, sample, options) if material is VACUUM: exc = ValueError("Material cannot be VACUUM.") erracc.add_exception(exc) self._validate_material(material, options, erracc)
def _validate_beam(self, beam, options, erracc): super()._validate_beam(beam, options, erracc) # Particle particle = apply_lazy(beam.particle, beam, options) if particle is not Particle.ELECTRON: exc = ValueError( "Particle {0} is not supported. Only ELECTRON.".format(particle) ) erracc.add_exception(exc)
def _validate_beam_cylindrical(self, beam, options, erracc): self._validate_beam_pencil(beam, options, erracc) # Diameter diameter_m = apply_lazy(beam.diameter_m, beam, options) if diameter_m < 0.0: exc = ValueError( "Diameter ({0:g} m) must be greater or equal to 0.0.".format( diameter_m)) erracc.add_exception(exc)
def _validate_analysis_kratio(self, analysis, options, erracc): standard_materials = apply_lazy(analysis.standard_materials, analysis, options) for z, material in standard_materials.items(): self._validate_material(material, options, erracc) if z not in material.composition: exc = ValueError( "Standard for element {0} does not have this element in its composition" .format(pyxray.element_symbol(z))) erracc.add_exception(exc)
def _export_sample_substrate(self, sample, options, erracc, geometry, dsmaxs): self._validate_sample_substrate(sample, options, erracc) # Geometry surface_cylinder = cylinder(100) # 100 cm radius surface_top = zplane(0.0) # z = 0 surface_bottom = zplane(-100) # z = -100 cm material = apply_lazy(sample.material, sample, options) penmaterial = self._export_material(material, options, erracc, index=1) module = Module(penmaterial, "Substrate") module.add_surface(surface_cylinder, SidePointer.NEGATIVE) module.add_surface(surface_top, SidePointer.NEGATIVE) module.add_surface(surface_bottom, SidePointer.POSITIVE) geometry.title = "Substrate" geometry.add_module(module) geometry.tilt_rad = apply_lazy(sample.tilt_rad, sample, options) geometry.rotation_rad = apply_lazy(sample.azimuth_rad, sample, options)
def _export_detector_photon(self, detector, options, erracc, input): self._validate_detector_photon(detector, options, erracc) # Azimuthal angles if isinstance(options.sample, (SubstrateSample, HorizontalLayerSample)): phi1 = 0 phi2 = 360 elif isinstance(options.sample, VerticalLayerSample): azimuth_deg = apply_lazy(detector.azimuth_deg, detector, options) azimuth_opening_deg = math.degrees( self.photon_detector_azimuth_opening_rad) phi1 = normalize_angle( math.radians(azimuth_deg - azimuth_opening_deg)) phi2 = normalize_angle( math.radians(azimuth_deg + azimuth_opening_deg)) phi1, phi2 = map(math.degrees, sorted([phi1, phi2])) else: phi1 = 0 phi2 = 360 # Elevation angles # Convert elevation angles (angle from the x-y plane) to theta angles used in PENEPMA, # defined as angle from the positive z-axis elevation_deg = apply_lazy(detector.elevation_deg, detector, options) elevation_opening_deg = math.degrees( self.photon_detector_elevation_opening_rad) theta1 = 90.0 - (elevation_deg + elevation_opening_deg) theta2 = 90.0 - (elevation_deg - elevation_opening_deg) # Energy windows # FIXME: Support spectrum # options.find_analyses(Spectrum, detector) ipsf = 0 edel = 0.0 edeu = options.beam.energy_eV nche = 10 input.photon_detectors.add(theta1, theta2, phi1, phi2, ipsf, edel, edeu, nche)