Skip to content

How to define your simulation (multibunch)

giadarol edited this page Aug 7, 2019 · 11 revisions

To define a multi-bunch simulation to be run with the PyPARIS ring of CPUs, the user needs to write a simulation class. Each CPU will instantiate a separate instance of the class, and use it to preform the simulation according to the paradigm defined here.

PyPARIS will add to the object a member called ring_of_CPUs, which carries the information about the multiprocess structure and allows each process to identify itself.

A prototype simulation class is defined in the following, and examples can be found in the PyPARIS test folders.

class Simulation(object):
    
    def __init__(self):
        self.N_turns = 5000
        self.N_buffer_float_size = 10000000
        self.N_buffer_int_size = 100
        self.N_parellel_rings = 10
        
        self.n_slices_per_bunch = 200
        self.z_cut_slicing = 3*sigma_z_bunch
        self.N_pieces_per_transfer = 300

    def pre_init_master(self):
        # Optional
        # Executed on the master at the very beginning of the simulation.
        # Returns a list of strings which is broadcast to all nodes 
        # and passed to init_all as "from_master"
        return list_of_strings
        
    def init_all(self, from_master): 
        # Executed on all cores at the beginning of the simulation
        #  - Generate the portion of the machine to be 
        #    simulated by the specific core.
        #  - Insert and initialize the e-cloud elements
        #  - At end-ring: prepare for global bunch operations
        if self.ring_of_CPUs.I_am_at_end_ring:    
            self.non_parallel_part=\
                 self.machine.one_turn_map[-n_non_sliceable:]
            
    def init_master(self):
        # ...arbitrary code...
        return list_bunches

    def init_master(self): 
        # Executed on the “master”, i.e. first core of first ring:
        #  - Initialize the queue with the bunches to be simulated
        return list_bunches 

    def init_start_ring(self): 
        # Executed at each core that is at the start of a ring:
        #  - Prepare bunch monitor
        self.bunch_monitor = ...                             

    def perform_bunch_operations_at_start_ring(self, bunch): 
        # Executed at each turn by cores at the start of each
        # ring:
        #  - Save bunch momenta

    def slice_bunch_at_start_ring(self, bunch): 
        # Executed by cores at the start of each ring:
        #  - Pop a bunch and slice it
        return list_slices 

    def treat_piece(self, slice): 
        # Executed by all cores:
        #  - Simulate the interaction of a slice with the
        #    assigned part of the ring
  
    def merge_slices_at_end_ring(self, list_slices): 
        # Executed by cores at the end of each ring:
        #  - Merge the slices back into a single bunch object
        return bunch 

    def perform_bunch_operations_at_end_ring(self, bunch): 
        # Executed by cores at the end of each ring:
        #  - Physics that needs to be performed globally on
        #    the bunch (e.g. lumped longitudinal tracking,
        #    bunch-by-bunch feedback)

    def piece_to_buffer(self, bunch):
        # Transform a bunch object into a float buffer for MPI 
        # communication.

    def buffer_to_piece(self, buffer):
        # Transform a float buffer from MPI communication 
        # into a bunch object

Clone this wiki locally