Source code for pymcxray.FileFormat.Results.ElectronTrajectoriesResults

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
.. py:currentmodule:: FileFormat.Results.ElectronTrajectoriesResults

.. moduleauthor:: Hendrix Demers <hendrix.demers@mail.mcgill.ca>

Read MCXray electron trajectories results file.
"""

###############################################################################
# Copyright 2017 Hendrix Demers
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
###############################################################################

# Standard library modules.
import os.path
import csv
import logging
import math

# Third party modules.
import matplotlib.pyplot as plt
import numpy as np

# Local modules.
from pymcxray import get_current_module_path

# Project modules

# Globals and constants variables.
COLOR_TRAJECTORY_TYPE = "colorTrajectoryType"
COLOR_REGION = "colorRegion"
COLOR_ENERGY = "colorEnergy"

COLLISION_TYPE_UNKNOWN = 0
COLLISION_TYPE_ELECTRON_GUN = 1
COLLISION_TYPE_REGION = 2
COLLISION_TYPE_OUT = 3
COLLISION_TYPE_EMPTY_REGION = 4
COLLISION_TYPE_ELASTIC = 5

HDF5_ELECTRON_TRAJECTORIES_RESULTS = "ElectronTrajectoriesResults"
HDF5_ELECTRON_TRAJECTORIES = "ElectronTrajectories"
HDF5_ELECTRON_TRAJECTORIES_TRAJECTORY_TYPE = 0
HDF5_ELECTRON_TRAJECTORIES_X_A = 1
HDF5_ELECTRON_TRAJECTORIES_Y_A = 2
HDF5_ELECTRON_TRAJECTORIES_Z_A = 3
HDF5_ELECTRON_TRAJECTORIES_CORRECTED_X_A = 4
HDF5_ELECTRON_TRAJECTORIES_CORRECTED_Y_A = 5
HDF5_ELECTRON_TRAJECTORIES_CORRECTED_Z_A = 6
HDF5_ELECTRON_TRAJECTORIES_ENERGY_keV = 7
HDF5_ELECTRON_TRAJECTORIES_INDEX_REGION = 8
HDF5_ELECTRON_TRAJECTORIES_COLLISION_TYPE = 9


[docs]class Collision(object): @property def x_A(self): return self._x_A @x_A.setter def x_A(self, x_A): self._x_A = x_A @property def y_A(self): return self._y_A @y_A.setter def y_A(self, y_A): self._y_A = y_A @property def z_A(self): return self._z_A @z_A.setter def z_A(self, z_A): self._z_A = z_A @property def correctedX_A(self): return self._correctedX_A @correctedX_A.setter def correctedX_A(self, correctedX_A): self._correctedX_A = correctedX_A @property def correctedY_A(self): return self._correctedY_A @correctedY_A.setter def correctedY_A(self, correctedY_A): self._correctedY_A = correctedY_A @property def correctedZ_A(self): return self._correctedZ_A @correctedZ_A.setter def correctedZ_A(self, correctedZ_A): self._correctedZ_A = correctedZ_A @property def energy_keV(self): return self._energy_keV @energy_keV.setter def energy_keV(self, energy_keV): self._energy_keV = energy_keV @property def indexRegion(self): return self._indexRegion @indexRegion.setter def indexRegion(self, indexRegion): self._indexRegion = indexRegion @property def collisionType(self): return self._collisionType @collisionType.setter def collisionType(self, collisionType): self._collisionType = collisionType
[docs]class Trajectory(object): def __init__(self): self._collisions = []
[docs] def addCollision(self, collision): self._collisions.append(collision)
@property def index(self): return self._index @index.setter def index(self, index): self._index = index @property def trajectoryType(self): return self._trajectoryType @trajectoryType.setter def trajectoryType(self, trajectoryType): self._trajectoryType = trajectoryType @property def collisions(self): return self._collisions @collisions.setter def collisions(self, collisions): self._collisions = collisions
[docs]class ElectronTrajectoriesResults(object): def __init__(self, filepath): self.number_trajectories = 0 self.maximum_number_collisions = 0 self.read(filepath)
[docs] def read(self, filepath): reader = csv.reader(open(filepath, 'r')) #Skip header line next(reader) self._trajectories = [] currentTrajectoryIndex = -1 trajectory = None for row in reader: trajectoryIndex = int(row[0]) trajectoryType = int(row[1]) if trajectoryIndex != currentTrajectoryIndex: if trajectory != None: self._trajectories.append(trajectory) self.number_trajectories += 1 self.maximum_number_collisions = max(self.maximum_number_collisions, number_collisions) trajectory = Trajectory() trajectory.index = trajectoryIndex trajectory.trajectoryType = trajectoryType currentTrajectoryIndex = trajectoryIndex number_collisions = 0 if len(row) == 8: collision = Collision() collision.x_A = float(row[2]) collision.y_A = float(row[3]) collision.z_A = float(row[4]) collision.energy_keV = float(row[5]) collision.indexRegion = int(row[6]) collision.collisionType = int(row[7]) elif len(row) == 11: collision = Collision() collision.x_A = float(row[2]) collision.y_A = float(row[3]) collision.z_A = float(row[4]) collision.correctedX_A = float(row[5]) collision.correctedY_A = float(row[6]) collision.correctedZ_A = float(row[7]) collision.energy_keV = float(row[8]) collision.indexRegion = int(row[9]) collision.collisionType = int(row[10]) trajectory.addCollision(collision) number_collisions += 1 logging.info("Number trajectories: %i", len(self._trajectories))
[docs] def write_hdf5(self, hdf5_group): hdf5_group = hdf5_group.require_group(HDF5_ELECTRON_TRAJECTORIES_RESULTS) shape = (10, self.number_trajectories, self.maximum_number_collisions) electron_trajectories_data = np.zeros(shape, dtype=float) for trajectory_id, trajectory in enumerate(self._trajectories): for collision_id, collision in enumerate(trajectory.collisions): electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_TRAJECTORY_TYPE, trajectory_id, collision_id] = trajectory.trajectoryType electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_X_A, trajectory_id, collision_id] = collision.x_A electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_Y_A, trajectory_id, collision_id] = collision.y_A electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_Z_A, trajectory_id, collision_id] = collision.z_A electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_CORRECTED_X_A, trajectory_id, collision_id] = collision.correctedX_A electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_CORRECTED_Y_A, trajectory_id, collision_id] = collision.correctedY_A electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_CORRECTED_Z_A, trajectory_id, collision_id] = collision.correctedZ_A electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_ENERGY_keV, trajectory_id, collision_id] = collision.energy_keV electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_INDEX_REGION, trajectory_id, collision_id] = collision.indexRegion electron_trajectories_data[HDF5_ELECTRON_TRAJECTORIES_COLLISION_TYPE, trajectory_id, collision_id] = collision.collisionType hdf5_group.create_dataset(HDF5_ELECTRON_TRAJECTORIES, data=electron_trajectories_data)
[docs] def getElectronGunPositions_nm(self): positions_nm = [] for trajectory in self._trajectories: for collision in trajectory.collisions: if collision.collisionType == COLLISION_TYPE_ELECTRON_GUN: position_nm = (collision.x_A*0.1, collision.y_A*0.1, collision.z_A*0.1) positions_nm.append(position_nm) assert len(positions_nm) == len(self._trajectories) return positions_nm
[docs] def drawXZ(self, title="", corrected=False, theta_deg=0.0, colorType=COLOR_TRAJECTORY_TYPE, trajectoryIndexes=None, x_limit=None, y_limit=None): theta_rad = math.radians(theta_deg) sinTheta = math.sin(theta_rad) cosTheta = math.cos(theta_rad) plt.figure() plt.title(title) indexUniqueRegionsAllTrajectories = set() if trajectoryIndexes is None: trajectoryIndexes = range(1, len(self._trajectories)+1) for trajectoryIndex in trajectoryIndexes: trajectory = self._trajectories[trajectoryIndex-1] if colorType == COLOR_TRAJECTORY_TYPE: color = self._getColor(trajectory.trajectoryType) x = [] z = [] for collision in trajectory.collisions: if corrected: x.append(collision.correctedX_A/10.0) z.append(collision.correctedZ_A/10.0) else: xx = collision.x_A/10.0 zz = collision.z_A/10.0 x.append(cosTheta*xx + sinTheta*zz) z.append(-sinTheta*xx + cosTheta*zz) plt.plot(x, z, '-', color=color) elif colorType == COLOR_REGION: color = self._getColor(trajectory.trajectoryType) x = [] z = [] indexRegions = [] indexUniqueRegions = set() for collision in trajectory.collisions: indexRegions.append(collision.indexRegion) indexUniqueRegions.add(collision.indexRegion) indexUniqueRegionsAllTrajectories.add(collision.indexRegion) if corrected: x.append(collision.correctedX_A/10.0) z.append(collision.correctedZ_A/10.0) else: xx = collision.x_A/10.0 zz = collision.z_A/10.0 x.append(cosTheta*xx + sinTheta*zz) z.append(-sinTheta*xx + cosTheta*zz) x = np.array(x) z = np.array(z) indexRegions = np.array(indexRegions) for indexRegion in sorted(indexUniqueRegions): zz = np.ma.masked_where(indexRegions != indexRegion, z) color = self._getColorRegion(indexRegion) plt.plot(x, zz, '.', color=color) plt.plot(x, z, '-', color="gray") plt.xlabel('X (nm)') plt.ylabel('Z (nm)') if x_limit is not None: plt.xlim(x_limit) if y_limit is not None: plt.ylim(y_limit) plt.grid(True) plt.gca().set_aspect('equal', 'datalim') plt.gca().invert_yaxis() print(sorted(indexUniqueRegionsAllTrajectories))
[docs] def drawXY(self, title="", corrected=False, x_limit=None, y_limit=None): plt.figure() plt.title(title) for trajectory in self._trajectories: color = self._getColor(trajectory.trajectoryType) x = [] y = [] for collision in trajectory.collisions: if corrected: x.append(collision.correctedX_A/10.0) y.append(collision.correctedY_A/10.0) else: x.append(collision.x_A/10.0) y.append(collision.y_A/10.0) plt.plot(x, y, '-', color=color) plt.xlabel('X (nm)') plt.ylabel('Y (nm)') if x_limit is not None: plt.xlim(x_limit) if y_limit is not None: plt.ylim(y_limit) plt.gca().set_aspect('equal', 'datalim') plt.grid(True)
[docs] def drawYZ(self, title="", corrected=False, x_limit=None, y_limit=None): plt.figure() plt.title(title) for trajectory in self._trajectories: color = self._getColor(trajectory.trajectoryType) y = [] z = [] for collision in trajectory.collisions: if corrected: y.append(collision.correctedY_A/10.0) z.append(collision.correctedZ_A/10.0) else: y.append(collision.y_A/10.0) z.append(collision.z_A/10.0) plt.plot(y, z, '-', color=color) plt.xlabel('Y (nm)') plt.ylabel('Z (nm)') if x_limit is not None: plt.xlim(x_limit) if y_limit is not None: plt.ylim(y_limit) plt.grid(True) plt.gca().set_aspect('equal', 'datalim') plt.gca().invert_yaxis()
def _getColor(self, trajectoryType): if trajectoryType == 1: color = 'b' elif trajectoryType == 2: color = 'r' elif trajectoryType == 3: color = 'b' elif trajectoryType == 4: color = 'm' return color def _getColorRegion(self, indexRegion): colors = ["blue", "green", "red", "black", "magenta", "yellow", "cyan"] if indexRegion < len(colors): color = colors[indexRegion] else: color = colors[indexRegion-len(colors)] return color
[docs]def run(): path = get_current_module_path(__file__, "../../../test_data/version1.2") filepath = os.path.join(path, "SimulationsComplexPhiRhoZ_Cr_T5nm_Z0nm_Al_E10d0keV_ElectronTrajectoriesResults.csv") #filepath = os.path.join(path, "SimulationsComplexPhiRhoZ_Cr100T50A_IsolatedLayer_E10d0keV_ElectronTrajectoriesResults.csv") electronTrajectoriesResults = ElectronTrajectoriesResults(filepath) electronTrajectoriesResults.drawXZ() electronTrajectoriesResults.drawXY() electronTrajectoriesResults.drawYZ() plt.show()
[docs]def runFogging(): path = r"K:\hdemers\results\simulations\MCXRay\foggingElectron" filepath = os.path.join(path, "McXRay_ElectronTrajectoriesResults.csv") electronTrajectoriesResults = ElectronTrajectoriesResults(filepath) electronTrajectoriesResults.drawXZ() electronTrajectoriesResults.drawXY() electronTrajectoriesResults.drawYZ() plt.show()
[docs]def runAuCThinFilm(): path = r"D:\work\results\simulations\MCXRay\SimulationAuCThinFilm\MCXRay_v1_4_6\simulations\Results" filepath = os.path.join(path, "SimulationAuCThinFilm_Au_d100A_C_E5d0keV_N1000000e_PX1000d0PY0d0nm_ElectronTrajectoriesResults.csv") electronTrajectoriesResults = ElectronTrajectoriesResults(filepath) electronTrajectoriesResults.drawXZ() #electronTrajectoriesResults.drawXY() #electronTrajectoriesResults.drawYZ() filepath = os.path.join(path, "SimulationAuCThinFilm_Au_d100A_C_E5d0keV_N1000000e_PX0d0PY0d0nm_ElectronTrajectoriesResults.csv") electronTrajectoriesResults = ElectronTrajectoriesResults(filepath) electronTrajectoriesResults.drawXZ() #electronTrajectoriesResults.drawXY() #electronTrajectoriesResults.drawYZ() plt.show()
if __name__ == '__main__': #pragma: no cover runAuCThinFilm()