Exemplo n.º 1
0
    def backengine(self):
        """ This method drives the backengine CrystFEL.pattern_sim."""

        # pattern_sim backengine does not support MPI.
        return self._run()

        # collect MPI arguments
        if self.parameters.forced_mpi_command == "":
            np = self.computeNTasks()
            mpicommand = ParallelUtilities.prepareMPICommandArguments(np)
        else:
            mpicommand = self.parameters.forced_mpi_command

        # Dump to a temporary file.
        fname = IOUtilities.getTmpFileName()
        self.dumpToFile(fname)

        mpicommand += " ".join([" ", sys.executable, __file__, fname])
        args = shlex.split(mpicommand)

        if 'SIMEX_VERBOSE' in os.environ and os.environ[
                'SIMEX_VERBOSE'] == 'MPI':
            print("MPI command: " + mpicommand)

        try:
            proc = subprocess.Popen(args, universal_newlines=True)
            proc.wait()
        except:
            raise
        finally:
            os.remove(fname)

        return proc.returncode
Exemplo n.º 2
0
    def testPrepareMPICommandArguments_Adds_ExtraMPIParameters(self):
        """ Test we correctly use SIMEX_EXTRA_MPI_PARAMETERS environment variable"""
        os.environ["SIMEX_EXTRA_MPI_PARAMETERS"]='blabla'

        self.assertIn("blabla",ParallelUtilities.prepareMPICommandArguments(10,0))

        del os.environ["SIMEX_EXTRA_MPI_PARAMETERS"]
Exemplo n.º 3
0
    def testVendorSpecificMPIArguments_UseAllThreads(self):
        """ Test we don't set OMP_NUM_THREADS by default"""

        version = dict([("Vendor", "OpenMPI"), ("Version", '1.6.0')])

        str = ParallelUtilities._getVendorSpecificMPIArguments(version, 0)
        self.assertNotIn("OMP_NUM_THREADS", str)
Exemplo n.º 4
0
    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(("WavePropagator 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
Exemplo n.º 5
0
    def testVendorSpecificMPIArguments_OpenMPINewVersion(self):
        """ Test mpirun arguments for OpenMPI are set correctly for new version."""
        version = dict([("Vendor", "OpenMPI"), ("Version", '1.9.0')])

        str = ParallelUtilities._getVendorSpecificMPIArguments(version, 1)
        self.assertEqual(
            str,
            " --map-by node --bind-to none -x OMP_NUM_THREADS=1 -x OMPI_MCA_mpi_warn_on_fork=0 -x OMPI_MCA_btl_base_warn_component_unused=0"
        )
Exemplo n.º 6
0
    def testResourceInfoFromSlurm_WorksForSingleNode(self):
        """ Test we can get resource info from SLURM for a single node."""
        os.environ['SLURM_JOB_NUM_NODES'] = '1'
        os.environ['SLURM_JOB_CPUS_PER_NODE'] = '40'

        resource = ParallelUtilities.getParallelResourceInfo()

        self.assertEqual(resource['NCores'], 40)
        self.assertEqual(resource['NNodes'], 1)
Exemplo n.º 7
0
    def testResourceInfoFromSlurm_WorksForMultipleNodeWithDifferentAmountOfCores(self):
        """ Test we can get resource info from SLURM for multiple heterogeneous nodes."""
        os.environ['SLURM_JOB_NUM_NODES']='3'
        os.environ['SLURM_JOB_CPUS_PER_NODE']='40x(2),20x(1),10x(10)'

        resource = ParallelUtilities.getParallelResourceInfo()

        self.assertEqual(resource['NCores'],200)
        self.assertEqual(resource['NNodes'],3)
Exemplo n.º 8
0
    def testVendorSpecificMPIArguments_OpenMPIOldVersion(self):
        """ Test mpirun arguments for OpenMPi are set correctly for old version."""
        version = dict([("Vendor", "OpenMPI"), ("Version", '1.6.0')])

        str = ParallelUtilities._getVendorSpecificMPIArguments(version, 1)
        self.assertEqual(
            str,
            " --bynode -x OMP_NUM_THREADS=1 -x OMPI_MCA_mpi_warn_on_fork=0 -x OMPI_MCA_btl_base_warn_component_unused=0 "
            "--mca mpi_cuda_support 0 --mca btl_openib_warn_no_device_params_found 0"
        )
Exemplo n.º 9
0
    def testResourceInfoFromSlurm_WorksForMultipleNodeWithSameAmountOfCores(
            self):
        """ Test we can get resource info from SLURM for multiple homogeneous nodes."""

        os.environ['SLURM_JOB_NUM_NODES'] = '3'
        os.environ['SLURM_JOB_CPUS_PER_NODE'] = '40(x3)'

        resource = ParallelUtilities.getParallelResourceInfo()

        self.assertEqual(resource['NCores'], 120 / self.threads_per_core)
        self.assertEqual(resource['NNodes'], 3)
Exemplo n.º 10
0
    def testGetVersionInfo(self):
        """ Test we can extract MPI version infromation."""
        version = ParallelUtilities._getMPIVersionInfo()

        self.assertIn('Vendor', version)
        self.assertIn('Version', version)
        self.assertIn(version['Vendor'], ["OpenMPI", "MPICH"])

        self.assertIsInstance(version['Version'], str)
        self.assertGreater(StrictVersion(version['Version']),
                           StrictVersion("0.0.0"))
Exemplo n.º 11
0
    def computeNTasks(self):
        resources = ParallelUtilities.getParallelResourceInfo()
        ncores = resources['NCores']
        nnodes = resources['NNodes']

        if self.parameters.cpus_per_task == "MAX":
            np = nnodes
        else:
            np = max(int(ncores / int(self.parameters.cpus_per_task)), 1)

        return np
Exemplo n.º 12
0
    def testResourceInfoNothingWorked(self):
        """ Test that we if we cannot get info, the  default values are used."""

        # we set SIMEX_MPICOMMAND so that it call return error
        os.environ["SIMEX_MPICOMMAND"] = 'blabla'

        resource = ParallelUtilities.getParallelResourceInfo()

        self.assertEqual(resource['NCores'], 0)
        self.assertEqual(resource['NNodes'], 1)

        del os.environ["SIMEX_MPICOMMAND"]
Exemplo n.º 13
0
    def testResourceInfoFromSimexWorks(self):
        """ Test we can set resource info via environment variables."""
        os.environ["SIMEX_NNODES"] = '1'
        os.environ["SIMEX_NCORES"] = '1'

        resource = ParallelUtilities.getParallelResourceInfo()

        self.assertEqual(resource['NCores'], 1)
        self.assertEqual(resource['NNodes'], 1)

        os.environ["SIMEX_NNODES"] = '-1'
        os.environ["SIMEX_NCORES"] = '-1'

        self.assertRaises(IOError, ParallelUtilities.getParallelResourceInfo)
Exemplo n.º 14
0
    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)
Exemplo n.º 15
0
    def computeNTasks(self):
        """ Calculate the number of MPI tasks as function of available resources and
        assigned cpus per task."""

        resources = ParallelUtilities.getParallelResourceInfo()
        ncores = resources['NCores']
        nnodes = resources['NNodes']

        if nnodes > 1:
            raise RuntimeError("Backengine does not support MPI parallelism. ")

        if self.parameters.cpus_per_task == "MAX":
            np = nnodes
        else:
            np = max(int(ncores / int(self.parameters.cpus_per_task)), 1)

        return np
Exemplo n.º 16
0
    def backengine(self):
        """ Starts EMC simulations in parallel in a subprocess """

        # Set paths.
        self._setupPaths()

        fname = IOUtilities.getTmpFileName()
        self.dumpToFile(fname)

        # collect MPI arguments
        if self.parameters.forced_mpi_command == "":
            np = self.computeNTasks()
            mpicommand = ParallelUtilities.prepareMPICommandArguments(np)
        else:
            mpicommand = self.parameters.forced_mpi_command
        # collect program arguments
        command_sequence = [
            'python',
            __file__,
            fname,
        ]
        # put MPI and program arguments together
        args = shlex.split(mpicommand) + command_sequence

        if 'SIMEX_VERBOSE' in os.environ:
            if 'MPI' in os.environ['SIMEX_VERBOSE']:
                print(("EMCOrientation backengine mpicommand: " + mpicommand))
            if 'PYTHON' in os.environ['SIMEX_VERBOSE']:
                import platform
                print("Running python version %s." %
                      (platform.python_version()))

        # Run the backengine command.
        proc = subprocess.Popen(args)
        proc.wait()

        os.remove(fname)

        # Return the return code from the backengine.
        return proc.returncode
Exemplo n.º 17
0
    def _backengineWithPdb(self):
        """ """
        """
        Run the diffraction simulation if the sample is a pdb.
        Codes is based on pysingfel/tests/test_particle.test_calFromPDB
        """

        # Dump self to file.
        fname = IOUtilities.getTmpFileName()
        self.dumpToFile(fname)

        # Setup the mpi call.
        forcedMPIcommand = self.parameters.forced_mpi_command

        if forcedMPIcommand == "" or forcedMPIcommand is None:
            (np, ncores) = self.computeNTasks()
            mpicommand = ParallelUtilities.prepareMPICommandArguments(
                np, ncores)
        else:
            mpicommand = forcedMPIcommand

        mpicommand += " ".join(("", sys.executable, __file__, fname))

        if 'SIMEX_VERBOSE' in os.environ:
            if 'MPI' in os.environ['SIMEX_VERBOSE']:
                print(("SingFELPhotonDiffractor backengine mpicommand: " +
                       mpicommand))

        # Launch the system command.
        args = shlex.split(mpicommand)
        with subprocess.Popen(args, universal_newlines=True) as proc:
            out, err = proc.communicate()

        # Remove the dumped class.
        os.remove(fname)

        return proc.returncode
Exemplo n.º 18
0
 def testResourceInfoFromMPI(self):
     """ Test we can get resource info from MPI command."""
     resource = ParallelUtilities.getParallelResourceInfo()
     self.assertGreater(resource['NCores'], 0)
     self.assertEqual(resource['NNodes'], 1)
Exemplo n.º 19
0
 def testPrepareMPICommandArguments_Adds_NumberOfTasks(self):
     """ Test we correctly set number of tasks"""
     self.assertIn("-np 10",
                   ParallelUtilities.prepareMPICommandArguments(10, 0))
Exemplo n.º 20
0
 def setUpClass(cls):
     """ Setting up the test class. """
     cls.threads_per_core = ParallelUtilities.getThreadsPerCoreFromSlurm()
Exemplo n.º 21
0
    def testVendorSpecificMPIArguments_MPICH(self):
        """ Test mpirun arguments for MPICH are set correctly."""
        version = dict([("Vendor", "MPICH"), ("Version", '1.9.0')])

        str = ParallelUtilities._getVendorSpecificMPIArguments(version, 1)
        self.assertEqual(str, " -map-by node -env OMP_NUM_THREADS 1")
Exemplo n.º 22
0
    def backengine(self):
        """ This method drives the backengine CrystFEL.pattern_sim."""

        # Setup directory structure as needed.
        if not os.path.isdir( self.output_path ):
            os.makedirs( self.output_path )
        output_file_base = os.path.join( self.output_path, "diffr_out")

        if self.parameters.number_of_diffraction_patterns == 1:
            output_file_base += "_0000001.h5"

        # collect MPI arguments
        if self.parameters.forced_mpi_command=="":
            np=self.computeNTasks()
            mpicommand=ParallelUtilities.prepareMPICommandArguments(np)
        else:
            mpicommand=self.parameters.forced_mpi_command

        # Setup command, minimum set first.
        command_sequence = ['pattern_sim',
                            '-p %s'                 % self.parameters.sample,
                            '--geometry=%s'         % self.parameters.detector_geometry,
                            '--output=%s'           % output_file_base,
                            '--number=%d'           % self.parameters.number_of_diffraction_patterns,
                            ]
        # Handle random rotation is requested.
        if self.parameters.uniform_rotation is True:
            command_sequence.append('--random-orientation')
            command_sequence.append('--really-random')

        if self.parameters.beam_parameters is not None:
            command_sequence.append('--photon-energy=%f' % (self.parameters.beam_parameters.photon_energy.m_as(electronvolt)))
            command_sequence.append('--beam-bandwidth=%f' % (self.parameters.beam_parameters.photon_energy_relative_bandwidth))
            nphotons = self.parameters.beam_parameters.pulse_energy / self.parameters.beam_parameters.photon_energy
            command_sequence.append('--nphotons=%e' % (nphotons))
            command_sequence.append('--beam-radius=%e' % (self.parameters.beam_parameters.beam_diameter_fwhm.m_as(meter)/2.))
            command_sequence.append('--spectrum=%s' % (self.parameters.beam_parameters.photon_energy_spectrum_type.lower()))
            if self.parameters.beam_parameters.photon_energy_spectrum_type.lower() == "sase":
                command_sequence.append('--sample-spectrum=512')

        # Handle intensities list if present.
        if self.parameters.intensities_file is not None:
            command_sequence.append('--intensities=%s' % (self.parameters.intensities_file))

        # Handle powder if present.
        if self.parameters.powder is True:
            command_sequence.append('--powder=%s' % (os.path.join(self.output_path, "powder.h5")))

        # Handle size range if present.
        if self.parameters.crystal_size_min is not None:
            command_sequence.append('--min-size=%f' % (self.parameters.crystal_size_min.m_as(1e-9*meter) ))
        if self.parameters.crystal_size_max is not None:
            command_sequence.append('--max-size=%f' % (self.parameters.crystal_size_max.m_as(1e-9*meter) ))


        # put MPI and program arguments together
        args = shlex.split(mpicommand) + command_sequence
        #args =  command_sequence
        command = " ".join(args)

        if 'SIMEX_VERBOSE' in os.environ:
            print("CrystFELPhotonDiffractor backengine command: "+command)

        # Run the backengine command.
        proc = subprocess.Popen(command, shell=True)
        proc.wait()

        # Return the return code from the backengine.
        return proc.returncode
Exemplo n.º 23
0
    def backengine(self):
        """ This method drives the backengine singFEL."""

        uniform_rotation = self.parameters.uniform_rotation
        calculate_Compton = int(self.parameters.calculate_Compton)
        slice_interval = self.parameters.slice_interval
        number_of_slices = self.parameters.number_of_slices
        pmi_start_ID = self.parameters.pmi_start_ID
        pmi_stop_ID = self.parameters.pmi_stop_ID
        number_of_diffraction_patterns = self.parameters.number_of_diffraction_patterns

        if not os.path.isdir(self.output_path):
            os.mkdir(self.output_path)
        self.__output_dir = self.output_path

        # If the sample is passed as a pdb, branch out to separate backengine implementation.
        if self.input_path.split(".")[-1].lower() == 'pdb':
            if not os.path.isfile(self.input_path):
                # Attempt to query from pdb.
                self.input_path = IOUtilities.checkAndGetPDB(self.input_path)

            return self._backengineWithPdb()

        # Ok, not a pdb, proceed.
        # Serialize the geometry file.
        beam_geometry_file = "tmp.geom"
        self.parameters.detector_geometry.serialize(beam_geometry_file)

        # Setup directory to pmi output.
        # Backengine expects a directory name, so have to check if
        # input_path is dir or file and handle accordingly.
        if os.path.isdir(self.input_path):
            input_dir = self.input_path

        elif os.path.isfile(self.input_path):
            input_dir = os.path.dirname(self.input_path)

        config_file = '/dev/null'

        # collect MPI arguments
        if self.parameters.forced_mpi_command == "":
            np, ncores = self.computeNTasks()
            mpicommand = ParallelUtilities.prepareMPICommandArguments(np,1)
        else:
            mpicommand = self.parameters.forced_mpi_command


# collect program arguments
        command_sequence = ['radiationDamageMPI',
                            '--inputDir',         str(input_dir),
                            '--outputDir',        str(self.__output_dir),
                            '--geomFile',         str(beam_geometry_file),
                            '--configFile',       str(config_file),
                            '--uniformRotation',  str(uniform_rotation),
                            '--calculateCompton', str(calculate_Compton),
                            '--sliceInterval',    str(slice_interval),
                            '--numSlices',        str(number_of_slices),
                            '--pmiStartID',       str(pmi_start_ID),
                            '--pmiEndID',         str(pmi_stop_ID),
                            '--numDP',            str(number_of_diffraction_patterns),
                            ]

        if self.parameters.beam_parameters is not None:
            beam_parameter_file = "tmp.beam"
            self.parameters.beam_parameters.serialize(beam_parameter_file)

            command_sequence.append('--beamFile')
            command_sequence.append(str(beam_parameter_file))

        # put MPI and program arguments together
        args = shlex.split(mpicommand) + command_sequence

        if 'SIMEX_VERBOSE' in os.environ:
            print(("SingFELPhotonDiffractor backengine command: "
                   + " ".join(args)),flush=True)

        # Run the backengine command.
        proc = subprocess.Popen(args)
        proc.wait()

        # Return the return code from the backengine.
        return proc.returncode