def set_periodic_checkpoint(sim, period, checkpoint_dir='./checkpoints'): """ Set up periodic checkpoints of the simulation The checkpoints are saved in openPMD format, in the specified directory, with one subdirectory per process. The E and B fields and particle information of each processor is saved. NB: Checkpoints are registered in the list `checkpoints` of the Simulation object `sim`, and written at the end of the PIC loop (whereas regular diagnostics are written at the beginning of the PIC loop). Parameters ---------- sim: a Simulation object The simulation that is to be saved in checkpoints period: integer The number of PIC iteration between each checkpoint. checkpoint_dir: string, optional The path to the directory in which the checkpoints are stored (When running a simulation with several MPI ranks, use the same path for all ranks.) """ # Only processor 0 creates a directory where checkpoints will be stored # Make sure that all processors wait until this directory is created # (Use the global MPI communicator instead of the `BoundaryCommunicator` # so that this still works in the case `use_all_ranks=False`) if comm.rank == 0: if os.path.exists(checkpoint_dir) is False: os.mkdir(checkpoint_dir) comm.barrier() # Choose the name of the directory: one directory per processor write_dir = os.path.join(checkpoint_dir, 'proc%d/' % comm.rank) # Register a periodic FieldDiagnostic in the diagnostics of the simulation # This saves only the E and B field (and their PML components, if used) fieldtypes = ["E", "B"] if sim.use_pml: fieldtypes += ["Er_pml", "Et_pml", "Br_pml", "Bt_pml"] sim.checkpoints.append( FieldDiagnostic(period, sim.fld, fieldtypes=fieldtypes, write_dir=write_dir)) # Register a periodic ParticleDiagnostic, which contains all # the particles which are present in the simulation particle_dict = {} for i in range(len(sim.ptcl)): particle_dict['species %d' % i] = sim.ptcl[i] if len(particle_dict) > 0: sim.checkpoints.append( ParticleDiagnostic(period, particle_dict, write_dir=write_dir))
def set_periodic_checkpoint(sim, period): """ Set up periodic checkpoints of the simulation The checkpoints are saved in openPMD format, in the directory `./checkpoints`, with one subdirectory per process. The E and B fields and particle information of each processor is saved. NB: Checkpoints are registered in the list `checkpoints` of the Simulation object `sim`, and written at the end of the PIC loop (whereas regular diagnostics are written at the beginning of the PIC loop). Parameters ---------- sim: a Simulation object The simulation that is to be saved in checkpoints period: integer The number of PIC iteration between each checkpoint. """ # Only processor 0 creates a directory where checkpoints will be stored # Make sure that all processors wait until this directory is created # (Use the global MPI communicator instead of the `BoundaryCommunicator` # so that this still works in the case `use_all_ranks=False`) if comm.rank == 0: if os.path.exists('./checkpoints') is False: os.mkdir('./checkpoints') comm.barrier() # Choose the name of the directory: one directory per processor write_dir = 'checkpoints/proc%d/' % comm.rank # Register a periodic FieldDiagnostic in the diagnostics of the simulation sim.checkpoints.append( FieldDiagnostic(period, sim.fld, fieldtypes=["E", "B"], write_dir=write_dir)) # Register a periodic ParticleDiagnostic, which contains all # the particles which are present in the simulation particle_dict = {} for i in range(len(sim.ptcl)): particle_dict['species %d' % i] = sim.ptcl[i] sim.checkpoints.append( ParticleDiagnostic(period, particle_dict, write_dir=write_dir))
def restart_from_checkpoint( sim, iteration=None ): """ Fills the Simulation object `sim` with data saved in a checkpoint. More precisely, the following data from `sim` is overwritten: - Current time and iteration number of the simulation - Position of the boundaries of the simulation box - Values of the field arrays - Size and values of the particle arrays Any other information (e.g. diagnostics of the simulation, presence of a moving window, presence of a laser antenna, etc.) need to be set by hand. For this reason, a successful restart will often require to modify the original input script that produced the checkpoint, rather than to start a new input script from scratch. NB: This function should always be called *before* the initialization of the moving window, since the moving window infers the position of particle injection from the existing particle data. Parameters ---------- sim: a Simulation object The Simulation object into which the checkpoint should be loaded iteration: integer (optional) The iteration number of the checkpoint from which to restart If None, the latest checkpoint available will be used. """ # Import openPMD-viewer try: from opmd_viewer import OpenPMDTimeSeries except ImportError: raise ImportError( 'The package `opmd_viewer` is required to restart from checkpoints.' '\nPlease install it from https://github.com/openPMD/openPMD-viewer') # Verify that the restart is valid (only for the first processor) # (Use the global MPI communicator instead of the `BoundaryCommunicator`, # so that this also works for `use_all_ranks=False`) if comm.rank == 0: check_restart( sim, iteration ) comm.barrier() # Choose the name of the directory from which to restart: # one directory per processor checkpoint_dir = 'checkpoints/proc%d/hdf5' %comm.rank ts = OpenPMDTimeSeries( checkpoint_dir ) # Select the iteration, and its index if iteration is None: iteration = ts.iterations[-1] # Find the index of the closest iteration i_iteration = np.argmin( abs(np.array(ts.iterations) - iteration) ) # Modify parameters of the simulation sim.iteration = iteration sim.time = ts.t[ i_iteration ] # Export available species as a list avail_species = ts.avail_species if avail_species is None: avail_species = [] # Load the particles # Loop through the different species if len(avail_species) == len(sim.ptcl): for i in range(len(sim.ptcl)): name = 'species %d' %i load_species( sim.ptcl[i], name, ts, iteration, sim.comm ) else: raise RuntimeError( \ """Species numbers in checkpoint and simulation should be same, but got {:d} and {:d}. Use add_new_species method to add species to simulation or sim.ptcl = [] to remove them""".format(len(avail_species), len(sim.ptcl)) ) # Record position of grid before restart zmin_old = sim.fld.interp[0].zmin # Load the fields # Loop through the different modes for m in range( sim.fld.Nm ): # Load the fields E and B for fieldtype in ['E', 'B']: for coord in ['r', 't', 'z']: load_fields( sim.fld.interp[m], fieldtype, coord, ts, iteration ) # Record position after restart (`zmin` is modified by `load_fields`) # and shift the global domain position in the BoundaryCommunicator zmin_new = sim.fld.interp[0].zmin sim.comm.shift_global_domain_positions( zmin_new - zmin_old )