Source code for SimEx.Calculators.XFELPhotonPropagator

""":module XFELPhotonPropagator: Module that holds the XFELPhotonPropagator class.  """
##########################################################################
#                                                                        #
# Copyright (C) 2015-2018 Carsten Fortmann-Grote                         #
# Contact: Carsten Fortmann-Grote <carsten.grote@xfel.eu>                #
#                                                                        #
# This file is part of simex_platform.                                   #
# simex_platform is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by   #
# the Free Software Foundation, either version 3 of the License, or      #
# (at your option) any later version.                                    #
#                                                                        #
# simex_platform is distributed in the hope that it will be useful,      #
# but WITHOUT ANY WARRANTY; without even the implied warranty of         #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          #
# GNU General Public License for more details.                           #
#                                                                        #
# You should have received a copy of the GNU General Public License      #
# along with this program.  If not, see <http://www.gnu.org/licenses/>.  #
#                                                                        #
##########################################################################


import os
import subprocess
import shlex

from SimEx.Calculators.AbstractPhotonPropagator import AbstractPhotonPropagator
from SimEx.Parameters.WavePropagatorParameters import WavePropagatorParameters
from SimEx.Utilities import EntityChecks
from SimEx.Utilities import IOUtilities
from SimEx.Utilities import ParallelUtilities
from SimEx.Utilities import wpg_to_opmd
from prop import propagate_s2e

[docs]class XFELPhotonPropagator(AbstractPhotonPropagator): """ :class XFELPhotonPropagator: Represents coherent wavefront propagation using the WPG wrapper for SWR. """ def __init__(self, parameters=None, input_path=None, output_path=None): """ :param parameters: Parameters for the photon propagation. :type parameters: WavePropagatorParameters instance. :param input_path: Location of input data for photon propagation. :type input_path: str, default 'FELsource/' :param output_path: Location of propagation output data. :type output_path: str, default 'prop/' """ # Handle default parameters if None. parameters = EntityChecks.checkAndSetInstance( WavePropagatorParameters, parameters, WavePropagatorParameters() ) # Initialize base class. super(XFELPhotonPropagator, self).__init__(parameters,input_path,output_path) def computeNTasks(self): resources=ParallelUtilities.getParallelResourceInfo() nnodes=resources['NNodes'] ncores=resources['NCores'] cpusPerTask=self.parameters.cpus_per_task if cpusPerTask=="MAX": np=nnodes ncores=0 else: np=max(1,int(ncores/int(cpusPerTask))) ncores=int(cpusPerTask) return (np,ncores)
[docs] def backengine(self): """ Starts WPG simulations in parallel in a subprocess """ fname = IOUtilities.getTmpFileName() self.dumpToFile(fname) forcedMPIcommand=self.parameters.forced_mpi_command if forcedMPIcommand=="": (np,ncores)=self.computeNTasks() mpicommand=ParallelUtilities.prepareMPICommandArguments(np,ncores) else: mpicommand=forcedMPIcommand if 'SIMEX_VERBOSE' in os.environ: if 'MPI' in os.environ['SIMEX_VERBOSE']: print(("XFELPhotonPropagator backengine mpicommand: "+mpicommand)) if 'PYTHON' in os.environ['SIMEX_VERBOSE']: import platform print("Running python %s." % ( platform.python_version() ) ) mpicommand+=" python "+__file__+" "+fname args = shlex.split(mpicommand) proc = subprocess.Popen(args,universal_newlines=True) proc.wait() os.remove(fname) return proc.returncode
def _run(self): """ This method drives the WPG backengine. :return: 0 if WPG returns successfully, 1 if not. """ # import should be here, not in header as it calls MPI_Init when imported. We want MPI to be # initialized at this stage only. from mpi4py import MPI # MPI info comm = MPI.COMM_WORLD thisProcess = comm.rank numProcesses = comm.size # Check if input path is a directory. if os.path.isdir(self.input_path): input_files = [ os.path.join( self.input_path, input_file ) for \ input_file in os.listdir( self.input_path ) ] input_files.sort() # Assuming the filenames have some kind of ordering scheme. else: if thisProcess == 0: # other MPI processes (if any) have nothing to do propagate_s2e.propagate(self.input_path, self.output_path, self.parameters.beamline.get_beamline) return 0 # If we have more than one input file, we should also have more than one output file, i.e. # output_path should be a directory. if os.path.isfile(self.output_path): raise IOError("The given output path is a file but a directory is needed. Cowardly refusing to overwrite.") # Check if output dir exists, create if not. if not os.path.isdir(self.output_path): os.mkdir(self.output_path) # Loop over all input files and generate one run per source file. for i,input_file in enumerate(input_files): ### TODO: Transmit number of cpus. # process file on a corresponding process (round-robin) if i % numProcesses == thisProcess: output_file = os.path.join( self.output_path, 'prop_out_%07d.h5' % (i) ) propagate_s2e.propagate(input_file, output_file, self.parameters.beamline.get_beamline) # Rewrite in openpmd conformant way. wpg_to_opmd.convertToOPMD( output_file ) return 0 @property def data(self): """ Query for the field data. """ return self.__data def _readH5(self): """ """ """ Private method for reading the hdf5 input and extracting the parameters and data relevant to initialize the object. """ pass # Nothing to be done since IO happens in backengine.
[docs] def saveH5(self): """ """ """ :param output_path: Path to propagation output. :type output_path: string """ pass # No action required since output is written in backengine.
if __name__ == '__main__': XFELPhotonPropagator.runFromCLI()