Пример #1
0
    def calculate(self,invars,Qpoints,lattice,traj_file):
        """
        calculate SQW from MD data
        """

        # this call does all of the 'work'
        self._loop_over_blocks(invars,Qpoints,lattice,traj_file)

        # average over the blocks
        if invars.compute_sqw:
            self.sqw = self.sqw/self.num_blocks 

        if invars.compute_bragg:
            self.bragg = self.bragg/self.num_blocks 

        if invars.compute_timeavg:
            self.timeavg = self.timeavg/self.num_blocks 

        # optionally save progress. 
        if invars.save_progress:

            if invars.compute_sqw:
                f_name = invars.outfile_prefix+f'_SQW_P{self.rank}_BF.hdf5' # final file
                mod_io.save_sqw(invars,Qpoints.reduced_Q,self.meV,self.sqw,f_name)

            if invars.compute_bragg:
                f_name = invars.outfile_prefix+f'_BRAGG_P{self.rank}_BF.hdf5'
                mod_io.save_bragg(invars,Qpoints.reduced_Q,self.bragg,f_name)
        
            if invars.compute_timeavg:
                f_name = invars.outfile_prefix+f'_TIMEAVG_P{self.rank}_BF.hdf5'
                mod_io.save_timeavg(invars,Qpoints.reduced_Q,self.timeavg,f_name)

        # free up memory (probably is already done by garbage collection)
        del self.pos, self.atom_types, self.xlengths
Пример #2
0
    def calculate(self, invars, Qpoints, lattice, traj_file):
        """
        calculate SQW from MD data
        """
        self._loop_over_blocks(invars, Qpoints, lattice, traj_file)

        self.sqw = self.sqw / self.num_blocks  # average over the blocks

        # optionally save progress
        if invars.save_progress:
            f_name = invars.outfile_prefix + f'_P{self.rank}_BF.hdf5'  # final file
            mod_io.save_sqw(invars, Qpoints.reduced_Q, self.meV, self.sqw,
                            f_name)

        del self.pos, self.atom_ids, self.b_array
Пример #3
0
    def _loop_over_blocks(self, invars, Qpoints, lattice, traj_file):
        """
        contains outer loop over blocks

        info about scattering lengths: there should be 1 length per TYPE, in order
        of types. e.g. for 4 types = 1,2,3,4 there should be for lenghts atom 1 : length 1,
        atom 2 : lenght 2, etc... i am also assuming that dump_modify sort id was used so
        that the order of atoms is the  same for each step. this can be changed easily if
        not the case using the atom_ids variable, but that will slow down the calc a little.
        the b_array variable has shape [num_steps, num_atoms] to vectorize calculating the
        neutron weighted density-density correlation fn
        """
        for block_index in invars.blocks:  # loop over blocks to 'ensemble' average

            self.block_index = block_index

            # print progress and start timer
            if self.rank == 0:
                start_time = timer()
                message = f'now on block {self.counter} out of {self.num_blocks}'
                print_stdout(message, msg_type='NOTE')

            # get the positions from file
            traj_file.parse_trajectory(invars, self)

            # check that the number of b's defined in file are consistent with traj
            if self.rank == 0:
                if np.unique(self.atom_ids[0, :]).shape[0] != invars.num_types:
                    message = 'number of types in input file doesnt match simulation'
                    raise PSF_exception(message)

            # set up array of scattering lengths.
            for aa in range(invars.num_atoms):
                self.b_array[0, aa] = invars.b[self.atom_ids[0, aa] - 1]
            self.b_array = np.tile(self.b_array[0, :].reshape(
                1, invars.num_atoms),
                                   reps=[self.block_steps, 1])

            # box lenghts read from traj file
            a = self.box_lengths[0] / invars.supercell[0]
            b = self.box_lengths[1] / invars.supercell[1]
            c = self.box_lengths[2] / invars.supercell[2]

            # print box lengths read from traj file to compare to input file
            if self.rank == 0:
                message = f'cell lengths from hdf5 file: {a:2.3f} {b:2.3f} {c:2.3f} Angstrom'
                print_stdout(message, msg_type='NOTE')

            # recall, only ortho lattice vectors used (for now)
            if invars.recalculate_cell_lengths:  # optionally recalculates from avg in MD file
                lattice.lattice_vectors = np.array([[a, 0, 0], [0, b, 0],
                                                    [0, 0, c]])
                lattice.recompute_lattice(
                    self.rank)  # recompute reciprocal lattice
                Qpoints.reconvert_Q_points(
                    lattice)  # convert Q to 1/A in new basis

            # do the loop over Q points
            if self.rank == 0:
                message = (
                    'printing progess for rank 0, which has >= the number of Q on other procs.\n'
                    ' -- now entering loop over Q -- ')
                print_stdout(message, msg_type='NOTE')

            for qq in range(Qpoints.Qsteps):

                if self.rank == 0:
                    message = f' now on Q-point {qq+1} out of {Qpoints.Qsteps}'
                    print_stdout(message)

                Q = Qpoints.Qpoints[qq, :].reshape(
                    (1, 3))  # these are the ones in 1/Angstrom
                exp_iQr = np.tile(
                    Q, reps=[self.block_steps, invars.num_atoms, 1]) * self.pos
                exp_iQr = np.exp(1j * exp_iQr.sum(axis=2)) * self.b_array
                self.sqw[:, qq] = self.sqw[:, qq] + np.abs(
                    fft(exp_iQr.sum(axis=1)))**2

            # print timing to the log file
            if self.rank == 0:
                end_time = timer()

                elapsed_time = (end_time - start_time) / 60  # minutes
                message = f' elapsed time for this block: {elapsed_time:2.3f} minutes'
                print_stdout(message, msg_type='TIMING')

                message = f' time per Q-point: {elapsed_time*60/Qpoints.Qsteps:2.3f} seconds'
                print_stdout(message)

            # optionally save progress
            if invars.save_progress:
                if self.counter != self.num_blocks:
                    f_name = invars.outfile_prefix + f'_P{self.rank}_B{block_index}.hdf5'
                    mod_io.save_sqw(invars, Qpoints.reduced_Q, self.meV,
                                    self.sqw / self.counter, f_name)

            self.counter = self.counter + 1  # update the counter
        """
Пример #4
0
        # gather all of the SQW results
        if invars.compute_sqw:

            # get from all ranks
            sqw_from_ranks = [sqw.sqw]
            for ii in range(1, num_ranks):
                sqw_ii = comm.recv(source=ii, tag=11)
                sqw_from_ranks.append(sqw_ii)

            # assemble the SQW results back into one
            sqw_total = np.zeros((sqw.num_freq, Qpoints.total_Qsteps))
            mod_utils.assemble_sqw(sqw_from_ranks, sqw_total)

            # save total SQW to final hdf5 file
            f_name = invars.outfile_prefix + f'_SQW_FINAL.hdf5'
            mod_io.save_sqw(invars, Qpoints.total_reduced_Q, sqw.meV,
                            sqw_total, f_name)

        # ---------------------------------------------------------------------

        # gather and save bragg results
        if invars.compute_bragg:

            # get from all ranks
            bragg_from_ranks = [sqw.bragg]
            for ii in range(1, num_ranks):
                bragg_ii = comm.recv(source=ii, tag=12)
                bragg_from_ranks.append(bragg_ii)

            # assemble into a single array
            bragg_total = np.zeros(Qpoints.total_Qsteps)
            mod_utils.assemble_timeavg(bragg_from_ranks, bragg_total)
Пример #5
0
    def _loop_over_blocks(self,invars,Qpoints,lattice,traj_file):
        """
        contains outer loop over blocks

        info about scattering lengths: there should be 1 length per TYPE, in order
        of types. e.g. for 4 types = 1,2,3,4 there should be for lengths atom 1 : length 1,
        atom 2 : lenght 2, etc... i am also assuming that dump_modify sort id was used so
        that the order of atoms is the  same for each step. this can be changed easily if
        not the case using the atom_types variable, but that will slow down the calc a little.
        the b_array variable has shape [num_steps, num_atoms] to vectorize calculating the
        neutron weighted density-density correlation fn
        """
        for block_index in invars.blocks: # loop over blocks to 'ensemble' average

            # used below
            self.block_index = block_index

            # print progress and start timer
            if self.rank == 0:
                start_time = timer()
                message = '\n............................................'
                print_stdout(message)
                message = f' now on block {self.counter} out of {self.num_blocks}'
                print_stdout(message,msg_type='NOTE')

            # get the positions from file
            traj_file.parse_trajectory(invars,self) 

            # check that the number of b's defined in input file are consistent with traj file
            if self.rank == 0:
                if np.unique(self.atom_types[0,:]).shape[0] != invars.num_types:
                    message = 'number of types in input file doesnt match simulation'
                    raise PSF_exception(message)

            # look up ins scattering lengths OR parameters to compute xray form factors.
            self.xlengths_tools.map_types_to_data(invars,self)

            # box lengths read from traj file
            a = self.box_lengths[0]/invars.supercell[0] 
            b = self.box_lengths[1]/invars.supercell[1]
            c = self.box_lengths[2]/invars.supercell[2]

            # print box lengths read from traj file to compare to input file
            if self.rank == 0:
                message = f'cell lengths from hdf5 file: {a:2.3f} {b:2.3f} {c:2.3f} Angstrom'
                print_stdout(message,msg_type='NOTE')

            # recall, only ortho lattice vectors used (for now)
            if invars.recalculate_cell_lengths: # optionally recalculates from avg in MD file
                lattice.lattice_vectors = np.array([[a,0,0],[0,b,0],[0,0,c]])
                lattice.recompute_lattice(self.rank)    # recompute reciprocal lattice
                Qpoints.reconvert_Q_points(lattice)     # convert Q to 1/A in new basis

            # --------------------- enter the loop over Qpoints -----------------------------------
            
            if self.rank == 0:
                Q_start_time = timer() # track time per Q not including the read/write time
                message = ('printing progess for rank 0, which has >= the number of Q on other procs.\n'
                            ' -- now entering loop over Q -- ')
                print_stdout(message,msg_type='NOTE')

            for qq in range(Qpoints.Qsteps):  

                if self.rank == 0:
                    message = f' now on Q-point {qq+1} out of {Qpoints.Qsteps}'
                    print_stdout(message)

                # the Qpoint to do
                Q = Qpoints.Qpoints[qq,:].reshape((1,3)) # 1/Angstrom
                self.Q_norm = np.sqrt(Q[0,0]**2+Q[0,1]**2+Q[0,2]**2)

                # if xray, need to compute f(|Q|), which are placed in self.xlengths
                if invars.exp_type == 'xray':
                    self.xlengths_tools.compute_xray_form_fact(self,invars)

                # space FT by vectorized Q.r dot products and sum over atoms. (tile prepends new axes)
                exp_iQr = np.tile(Q,reps=[self.block_steps,invars.num_atoms,1])*self.pos # Q.r
                exp_iQr = np.exp(1j*exp_iQr.sum(axis=2))*self.xlengths # sum over x, y, z
                exp_iQr = exp_iQr.sum(axis=1) # sum over atoms

                # compute bragg intensity = |<rho(Q,t)>|**2
                if invars.compute_bragg:
                    self.bragg[qq] = self.bragg[qq]+np.abs((exp_iQr).mean())**2/self.common_rescale

                # compute timeavg intensity = <|rho(Q,t)|**2>
                if invars.compute_timeavg:
                    self.timeavg[qq] = self.timeavg[qq]+(np.abs(exp_iQr)**2).mean()/self.common_rescale

                # compute dynamical intensity = |rho(Q,w)|**2
                if invars.compute_sqw:
                    self.sqw[:,qq] = (self.sqw[:,qq]+np.abs(fft(exp_iQr))**2/
                                                    self.sqw_norm/self.common_rescale)

            # -------------------------------------------------------------------------------------

            # optionally save progress
            if invars.save_progress:

                if self.counter != self.num_blocks:

                    if invars.compute_sqw:
                        f_name = invars.outfile_prefix+f'_SQW_P{self.rank}_B{block_index}.hdf5'
                        mod_io.save_sqw(invars,Qpoints.reduced_Q,self.meV,self.sqw/self.counter,f_name)

                    if invars.compute_bragg:
                        f_name = invars.outfile_prefix+f'_BRAGG_P{self.rank}_B{block_index}.hdf5'
                        mod_io.save_bragg(invars,Qpoints.reduced_Q,self.bragg,f_name)

                    if invars.compute_timeavg:
                        f_name = invars.outfile_prefix+f'_TIMEAVG_P{self.rank}_B{block_index}.hdf5'
                        mod_io.save_timeavg(invars,Qpoints.reduced_Q,self.timeavg,f_name)

            # print timing to the log file
            if self.rank == 0:

                end_time = timer()
                elapsed_time = end_time-start_time
                Q_time = end_time-Q_start_time
                io_time = elapsed_time-Q_time

                Q_time = Q_time/Qpoints.Qsteps # avg over all Q
                message = f' avg time per Q-point:      {Q_time:2.3f} seconds'
                print_stdout(message,msg_type='TIMING')

                message = f' total io time:             {io_time:2.3f} seconds'
                print_stdout(message)

                message = (f' total time for this block: {elapsed_time:2.3f} seconds'
                           f' ({elapsed_time/60:2.3f} minutes)')
                print_stdout(message)

            self.counter = self.counter+1 # update the counter
Пример #6
0
    def _loop_over_blocks(self,invars,Qpoints,lattice,traj_file):

        """
        contains outer loop over blocks

        info about scattering lengths: there should be 1 length per TYPE, in order
        of types. e.g. for 4 types = 1,2,3,4 there should be for lengths atom 1 : length 1,
        atom 2 : lenght 2, etc... i am also assuming that dump_modify sort id was used so
        that the order of atoms is the  same for each step. this can be changed easily if
        not the case using the atom_types variable, but that will slow down the calc a little.
        the b_array variable has shape [num_steps, num_atoms] to vectorize calculating the
        neutron weighted density-density correlation fn
        """

        for block_index in invars.blocks: # loop over blocks to 'ensemble' average

            # used below
            self.block_index = block_index

            # print progress and start timer
            start_time = timer()
            message = '\n............................................'
            print_stdout(message)
            message = f' now on block {self.counter} out of {self.num_blocks}'
            print_stdout(message,msg_type='NOTE')

            # get the positions from file
            traj_file.parse_trajectory(invars,self) 

            # check that the number of b's defined in input file are consistent with traj file
            if np.unique(self.atom_types[0,:]).shape[0] != invars.num_types:
                message = 'number of types in input file doesnt match simulation'
                raise PSF_exception(message)

            # look up ins scattering lengths OR parameters to compute xray form factors.
            self.xlengths_tools.map_types_to_data(invars,self)

            # box lengths read from traj file
            a = self.box_lengths[0]/invars.supercell[0] 
            b = self.box_lengths[1]/invars.supercell[1]
            c = self.box_lengths[2]/invars.supercell[2]

            # print box lengths read from traj file to compare to input file
            message = f'cell lengths from hdf5 file: {a:2.3f} {b:2.3f} {c:2.3f} Angstrom'
            print_stdout(message,msg_type='NOTE')

            # recall, only ortho lattice vectors used (for now)
            if invars.recalculate_cell_lengths: # optionally recalculates from avg in MD file
                lattice.lattice_vectors = np.array([[a,0,0],[0,b,0],[0,0,c]])
                lattice.recompute_lattice()         # recompute reciprocal lattice
                Qpoints.reconvert_Q_points(lattice) # convert Q to 1/A in new basis

            Q_start_time = timer() # track time per Q not including the read/write time

            message = ('printing progess for process 0, which has >= the number of Q on other' \
                    ' processes.\n -- now entering loop over Q -- ')
            print_stdout(message,msg_type='NOTE')

            # -----------------------------------------------------------------------------------------
            #                 ------------- multiprocessing part. -------------
            # -----------------------------------------------------------------------------------------
            
            # a Queue to hold the retured SQW data
            self.mp_queue = mp.Queue()

            # a container to hold the processes
            procs = []

            # loop over processes, setting up the loop over Q on each.
            for pp in range(invars.num_processes):
                procs.append(mp.Process(target=self._loop_over_Q, args=(pp,invars,Qpoints)))

            # now start running the function on each process
            for proc in procs:
                proc.start()

            # note, doing it this way with the queue 'blocks' until the next processes adds to queue if 
            # it is empty. I dont know if this will freeze the whole calculation or just the background 
            # proc that is running the queue. anyway, everything with the queue has to be done before
            # joining the procs or the data will corrupt/crash the program.

            # get the stuff calculated on each proc
            for pp in range(invars.num_processes):

                sqw_pp, bragg_pp, timeavg_pp, proc = self.mp_queue.get()
                Q_inds = Qpoints.Q_on_procs[proc]

                # now put it into main arrays if requested
                if invars.compute_sqw:
                    self.sqw[:,Q_inds] = self.sqw[:,Q_inds]+sqw_pp
                if invars.compute_bragg:
                    self.bragg[Q_inds] = self.bragg[Q_inds]+bragg_pp
                if invars.compute_timeavg:
                    self.timeavg[Q_inds] = self.timeavg[Q_inds]+timeavg_pp

            # now close the queue and rejoin its proc
            self.mp_queue.close()
            self.mp_queue.join_thread()

            # wait here for all to finish before moving on to the next block
            for proc in procs:
                proc.join()

            # -----------------------------------------------------------------------------------------
            #                 ------------ end of multiprocessing part ----------------
            # -----------------------------------------------------------------------------------------

            # optionally save progress
            if invars.save_progress:

                if self.counter != self.num_blocks: # dont write if this is the last block

                    if invars.compute_sqw:
                        f_name = invars.outfile_prefix+f'_SQW_B{block_index}.hdf5'
                        mod_io.save_sqw(invars,Qpoints.reduced_Q,self.meV,self.sqw/self.counter,f_name)

                    if invars.compute_bragg:
                        f_name = invars.outfile_prefix+f'_BRAGG_B{block_index}.hdf5'
                        mod_io.save_bragg(invars,Qpoints.reduced_Q,self.bragg/self.counter,f_name)

                    if invars.compute_timeavg:
                        f_name = invars.outfile_prefix+f'_TIMEAVG_B{block_index}.hdf5'
                        mod_io.save_timeavg(invars,Qpoints.reduced_Q,self.timeavg/self.counter,f_name)

            # print timing to screen
            end_time = timer()
            elapsed_time = end_time-start_time
            Q_time = end_time-Q_start_time
            io_time = elapsed_time-Q_time

            # time per Qpoint
            Q_time = Q_time/len(Qpoints.Q_on_procs[0]) # avg over all Q
            message = f' avg time per Q-point:      {Q_time:2.3f} seconds'
            print_stdout(message,msg_type='TIMING')

            # time spent in i/o
            message = f' total io time:             {io_time:2.3f} seconds'
            print_stdout(message)

            # total time for in this method
            message = (f' total time for this block: {elapsed_time:2.3f} seconds'
                        f' ({elapsed_time/60:2.3f} minutes)')
            print_stdout(message)

            # update the block counter
            self.counter = self.counter+1