void
nest::SimulationManager::reset_network()
{
    if ( not has_been_simulated() )
        return; // nothing to do


    kernel().event_delivery_manager.clear_pending_spikes();

    kernel().node_manager.reset_nodes_state();

    // ConnectionManager doesn't support resetting dynamic synapses yet
    LOG( M_WARNING,
         "SimulationManager::ResetNetwork",
         "Synapses with internal dynamics (facilitation, STDP) are not reset.\n"
         "This will be implemented in a future version of NEST." );
}
void
nest::SimulationManager::set_status( const DictionaryDatum& d )
{
    // Create an instance of time converter here to capture the current
    // representation of time objects: TICS_PER_MS and TICS_PER_STEP
    // will be stored in time_converter.
    // This object can then be used to convert times in steps
    // (e.g. Connection::delay_) or tics to the new representation.
    // We pass this object to ConnectionManager::calibrate to update
    // all time objects in the connection system to the new representation.
    // MH 08-04-14
    TimeConverter time_converter;

    double_t time;
    if ( updateValue< double_t >( d, "time", time ) )
    {
        if ( time != 0.0 )
            throw BadProperty( "The simulation time can only be set to 0.0." );

        if ( clock_ > TimeZero )
        {
            // reset only if time has passed
            LOG( M_WARNING,
                 "SimulationManager::set_status",
                 "Simulation time reset to t=0.0. Resetting the simulation time is not "
                 "fully supported in NEST at present. Some spikes may be lost, and "
                 "stimulating devices may behave unexpectedly. PLEASE REVIEW YOUR "
                 "SIMULATION OUTPUT CAREFULLY!" );

            clock_ = Time::step( 0 );
            from_step_ = 0;
            slice_ = 0;
            // clear all old spikes
            kernel().event_delivery_manager.configure_spike_buffers();
        }
    }

    updateValue< bool >( d, "print_time", print_time_ );

    // tics_per_ms and resolution must come after local_num_thread /
    // total_num_threads because they might reset the network and the time
    // representation
    nest::double_t tics_per_ms = 0.0;
    bool tics_per_ms_updated =
        updateValue< nest::double_t >( d, "tics_per_ms", tics_per_ms );
    double_t resd = 0.0;
    bool res_updated = updateValue< double_t >( d, "resolution", resd );

    if ( tics_per_ms_updated || res_updated )
    {
        if ( kernel().node_manager.size() > 1 ) // root always exists
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Cannot change time representation after nodes have been created. "
                 "Please call ResetKernel first." );
            throw KernelException();
        }
        else if ( has_been_simulated() ) // someone may have simulated empty network
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Cannot change time representation after the network has been "
                 "simulated. Please call ResetKernel first." );
            throw KernelException();
        }
        else if ( kernel().connection_manager.get_num_connections() != 0 )
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Cannot change time representation after connections have been "
                 "created. Please call ResetKernel first." );
            throw KernelException();
        }
        else if ( res_updated && tics_per_ms_updated ) // only allow TICS_PER_MS to
            // be changed together with
            // resolution
        {
            if ( resd < 1.0 / tics_per_ms )
            {
                LOG( M_ERROR,
                     "SimulationManager::set_status",
                     "Resolution must be greater than or equal to one tic. Value "
                     "unchanged." );
                throw KernelException();
            }
            else
            {
                nest::Time::set_resolution( tics_per_ms, resd );
                // adjust to new resolution
                clock_.calibrate();
                // adjust delays in the connection system to new resolution
                kernel().connection_manager.calibrate( time_converter );
                kernel().model_manager.calibrate( time_converter );
                LOG( M_INFO,
                     "SimulationManager::set_status",
                     "tics per ms and resolution changed." );

                // make sure that wfr communication interval is always greater or equal
                // to resolution if no wfr is used explicitly set wfr_comm_interval
                // to resolution because communication in every step is needed
                if ( wfr_comm_interval_ < Time::get_resolution().get_ms()
                        || not use_wfr_ )
                {
                    wfr_comm_interval_ = Time::get_resolution().get_ms();
                }
            }
        }
        else if ( res_updated ) // only resolution changed
        {
            if ( resd < Time::get_ms_per_tic() )
            {
                LOG( M_ERROR,
                     "SimulationManager::set_status",
                     "Resolution must be greater than or equal to one tic. Value "
                     "unchanged." );
                throw KernelException();
            }
            else
            {
                Time::set_resolution( resd );
                clock_.calibrate(); // adjust to new resolution
                // adjust delays in the connection system to new resolution
                kernel().connection_manager.calibrate( time_converter );
                kernel().model_manager.calibrate( time_converter );
                LOG( M_INFO,
                     "SimulationManager::set_status",
                     "Temporal resolution changed." );

                // make sure that wfr communication interval is always greater or equal
                // to resolution if no wfr is used explicitly set wfr_comm_interval
                // to resolution because communication in every step is needed
                if ( wfr_comm_interval_ < Time::get_resolution().get_ms()
                        || not use_wfr_ )
                {
                    wfr_comm_interval_ = Time::get_resolution().get_ms();
                }
            }
        }
        else
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "change of tics_per_step requires simultaneous specification of "
                 "resolution." );
            throw KernelException();
        }
    }

    // The decision whether the waveform relaxation is used
    // must be set before nodes are created.
    // Important: wfr_comm_interval_ may change depending on use_wfr_
    bool wfr;
    if ( updateValue< bool >( d, "use_wfr", wfr ) )
    {
        if ( kernel().node_manager.size() > 1 )
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Cannot enable/disable usage of waveform relaxation after nodes have "
                 "been created. Please call ResetKernel first." );
            throw KernelException();
        }
        else
        {
            use_wfr_ = wfr;
            // if no wfr is used explicitly set wfr_comm_interval to resolution
            // because communication in every step is needed
            if ( not use_wfr_ )
            {
                wfr_comm_interval_ = Time::get_resolution().get_ms();
            }
        }
    }

    // wfr_comm_interval_ can only be changed if use_wfr_ is true and before
    // connections are created. If use_wfr_ is false wfr_comm_interval_ is set to
    // the resolution whenever the resolution changes.
    double_t wfr_interval;
    if ( updateValue< double_t >( d, "wfr_comm_interval", wfr_interval ) )
    {
        if ( not use_wfr_ )
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Cannot set waveform communication interval when usage of waveform "
                 "relaxation is disabled. Set use_wfr to true first." );
            throw KernelException();
        }
        else if ( kernel().connection_manager.get_num_connections() != 0 )
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Cannot change waveform communication interval after connections have "
                 "been created. Please call ResetKernel first." );
            throw KernelException();
        }
        else if ( wfr_interval < Time::get_resolution().get_ms() )
        {
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Communication interval of the waveform relaxation must be greater or "
                 "equal to the resolution of the simulation." );
            throw KernelException();
        }
        else
        {
            LOG( M_INFO,
                 "SimulationManager::set_status",
                 "Waveform communication interval changed successfully. " );
            wfr_comm_interval_ = wfr_interval;
        }
    }

    // set the convergence tolerance for the waveform relaxation method
    double_t tol;
    if ( updateValue< double_t >( d, "wfr_tol", tol ) )
    {
        if ( tol < 0.0 )
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Tolerance must be zero or positive" );
        else
            wfr_tol_ = tol;
    }

    // set the maximal number of iterations for the waveform relaxation method
    long max_iter;
    if ( updateValue< long >( d, "wfr_max_iterations", max_iter ) )
    {
        if ( max_iter <= 0 )
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Maximal number of iterations  for the waveform relaxation must be "
                 "positive. To disable waveform relaxation set use_wfr instead." );
        else
            wfr_max_iterations_ = max_iter;
    }

    // set the interpolation order for the waveform relaxation method
    long interp_order;
    if ( updateValue< long >( d, "wfr_interpolation_order", interp_order ) )
    {
        if ( ( interp_order < 0 ) || ( interp_order == 2 ) || ( interp_order > 3 ) )
            LOG( M_ERROR,
                 "SimulationManager::set_status",
                 "Interpolation order must be 0, 1, or 3." );
        else
            wfr_interpolation_order_ = interp_order;
    }
}
void
nest::SimulationManager::set_status( const DictionaryDatum& d )
{
  // Create an instance of time converter here to capture the current
  // representation of time objects: TICS_PER_MS and TICS_PER_STEP
  // will be stored in time_converter.
  // This object can then be used to convert times in steps
  // (e.g. Connection::delay_) or tics to the new representation.
  // We pass this object to ConnectionManager::calibrate to update
  // all time objects in the connection system to the new representation.
  // MH 08-04-14
  TimeConverter time_converter;

  double_t time;
  if ( updateValue< double_t >( d, "time", time ) )
  {
    if ( time != 0.0 )
      throw BadProperty( "The simulation time can only be set to 0.0." );

    if ( clock_ > TimeZero )
    {
      // reset only if time has passed
      LOG( M_WARNING,
        "SimulationManager::set_status",
        "Simulation time reset to t=0.0. Resetting the simulation time is not "
        "fully supported in NEST at present. Some spikes may be lost, and "
        "stimulating devices may behave unexpectedly. PLEASE REVIEW YOUR "
        "SIMULATION OUTPUT CAREFULLY!" );

      clock_ = Time::step( 0 );
      from_step_ = 0;
      slice_ = 0;
      kernel().event_delivery_manager.configure_spike_buffers(); // clear all old spikes
    }
  }

  updateValue< bool >( d, "print_time", print_time_ );

  // tics_per_ms and resolution must come after local_num_thread / total_num_threads
  // because they might reset the network and the time representation
  nest::double_t tics_per_ms;
  bool tics_per_ms_updated = updateValue< nest::double_t >( d, "tics_per_ms", tics_per_ms );
  double_t resd;
  bool res_updated = updateValue< double_t >( d, "resolution", resd );

  if ( tics_per_ms_updated || res_updated )
  {
    if ( kernel().node_manager.size() > 1 ) // root always exists
    {
      LOG( M_ERROR,
        "SimulationManager::set_status",
        "Cannot change time representation after nodes have been created. Please call ResetKernel "
        "first." );
      throw KernelException();
    }
    else if ( has_been_simulated() ) // someone may have simulated empty network
    {
      LOG( M_ERROR,
        "SimulationManager::set_status",
        "Cannot change time representation after the network has been simulated. Please call "
        "ResetKernel first." );
      throw KernelException();
    }
    else if ( kernel().connection_builder_manager.get_num_connections() != 0 )
    {
      LOG( M_ERROR,
        "SimulationManager::set_status",
        "Cannot change time representation after connections have been created. Please call "
        "ResetKernel first." );
      throw KernelException();
    }
    else if ( res_updated
      && tics_per_ms_updated ) // only allow TICS_PER_MS to be changed together with resolution
    {
      if ( resd < 1.0 / tics_per_ms )
      {
        LOG( M_ERROR,
          "SimulationManager::set_status",
          "Resolution must be greater than or equal to one tic. Value unchanged." );
        throw KernelException();
      }
      else
      {
        nest::Time::set_resolution( tics_per_ms, resd );
        clock_.calibrate(); // adjust to new resolution
        // adjust delays in the connection system to new resolution
        kernel().connection_builder_manager.calibrate( time_converter );
        kernel().model_manager.calibrate( time_converter );
        LOG( M_INFO, "SimulationManager::set_status", "tics per ms and resolution changed." );
      }
    }
    else if ( res_updated ) // only resolution changed
    {
      if ( resd < Time::get_ms_per_tic() )
      {
        LOG( M_ERROR,
          "SimulationManager::set_status",
          "Resolution must be greater than or equal to one tic. Value unchanged." );
        throw KernelException();
      }
      else
      {
        Time::set_resolution( resd );
        clock_.calibrate(); // adjust to new resolution
        // adjust delays in the connection system to new resolution
        kernel().connection_builder_manager.calibrate( time_converter );
        kernel().model_manager.calibrate( time_converter );
        LOG( M_INFO, "SimulationManager::set_status", "Temporal resolution changed." );
      }
    }
    else
    {
      LOG( M_ERROR,
        "SimulationManager::set_status",
        "change of tics_per_step requires simultaneous specification of resolution." );
      throw KernelException();
    }
  }

  // set the number of preliminary update cycles
  // e.g. for the implementation of gap junctions
  long nprelim;
  if ( updateValue< long >( d, "max_num_prelim_iterations", nprelim ) )
  {
    if ( nprelim < 0 )
      LOG( M_ERROR,
        "SimulationManager::set_status",
        "Number of preliminary update iterations must be zero or positive." );
    else
      max_num_prelim_iterations_ = nprelim;
  }

  double_t tol;
  if ( updateValue< double_t >( d, "prelim_tol", tol ) )
  {
    if ( tol < 0.0 )
      LOG( M_ERROR, "SimulationManager::set_status", "Tolerance must be zero or positive" );
    else
      prelim_tol_ = tol;
  }

  long interp_order;
  if ( updateValue< long >( d, "prelim_interpolation_order", interp_order ) )
  {
    if ( ( interp_order < 0 ) || ( interp_order == 2 ) || ( interp_order > 3 ) )
      LOG( M_ERROR, "SimulationManager::set_status", "Interpolation order must be 0, 1, or 3." );
    else
      prelim_interpolation_order_ = interp_order;
  }
}