def run_simulation(adjacency_matrix=None,
                   weight=None,
                   noise_rate=NOISE_RATE,
                   noise_weight=NOISE_WEIGHT,
                   resolution=RESOLUTION,
                   simtime=SIMTIME_RUN,
                   save=False, output_path='data/', basename='nest_sim_',
                   overwrite=False, verbose=True, print_time=False):

    if adjacency_matrix is None:
        # construct a network according to defaults
        adjacency_matrix = fake_network.construct_network()

    if weight is None:
        # if unspecified, find the weight automatically according to defaults
        weight, _ = adjust_weight(adjacency_matrix, noise_weight=noise_weight,
                                  noise_rate=noise_rate, resolution=resolution,
                                  verbose=verbose, print_time=print_time)

    # convert into network_object
    network_obj = adjacency2netobj(adjacency_matrix)

    ncells, ncons, neuronsE, espikes, noise, GIDoffset = create_network(
        network_obj, weight, noise_weight, noise_rate, resolution=resolution,
        verbose=verbose, print_time=print_time,
    )

    if verbose:
        print 'Simulating %s of activity for %i neurons' % (
            s2h(simtime / 1000.), ncells)

    startsimulate = time.time()
    nest.Simulate(simtime)
    endsimulate = time.time()

    sim_elapsed = endsimulate - startsimulate

    totalspikes = nest.GetStatus(espikes, "n_events")[0]
    events = nest.GetStatus(espikes, "events")[0]

    # NEST increments the GID whenever a new node is created. we therefore
    # subtract the GID offset, so that the output cell indices are correct
    # regardless of when the corresponding nodes were created in NEST
    cell_indices = events["senders"] - GIDoffset
    spike_times = events["times"]

    burst_rate = determine_burst_rate(spike_times, simtime, ncells)

    if verbose:
        print "\n" + "-" * 60
        print "Number of neurons: ", ncells
        print "Number of spikes recorded: ", totalspikes
        print "Avg. spike rate of neurons: %.2f Hz" % (
            totalspikes / (ncells * simtime / 1000.))
        print "Network burst rate: %.2f Hz" % burst_rate
        print "Simulation time: %s" % s2h(sim_elapsed)
        print "-" * 60

    # resample at 50Hz to make an [ncells, ntimesteps] array of bin counts
    resampled = resample_spikes(spike_times, cell_indices,
                                output_resolution=20, simtime=simtime,
                                ncells=ncells)

    if save:

        today = str(datetime.date.today())
        fname = basename + today
        if os.path.exists(fname) & ~overwrite:
            suffix = 0
            while os.path.exists(fname):
                suffix += 1
                fname = '%s%s_%i.npz' % (basename, today, suffix)
        fullpath = os.path.join(output_path, fname)
        np.savez(fullpath, spike_times=spike_times, cell_indices=cell_indices,
                 resampled=resampled)

        if verbose:
            print "Saved output in '%s'" % fullpath

    return spike_times, cell_indices, resampled
def adjust_weight(adjacency_matrix=None,
                  burstrate_target=BURSTRATE_TARGET,
                  burstrate_tol=BURSTRATE_TOL,
                  weight=JE_WEIGHT_INIT,
                  noise_weight=NOISE_WEIGHT,
                  noise_rate=NOISE_RATE,
                  resolution=RESOLUTION,
                  simtime=SIMTIME_ADAPT,
                  maxiter_adapt=MAXITER_ADAPT,
                  verbose=True,
                  print_time=False,
                  ):

    if adjacency_matrix is None:
        # construct a default network
        adjacency_matrix = fake_network.construct_network()

    # convert into network_object
    network_obj = adjacency2netobj(adjacency_matrix)

    adaptParList = []
    burst_rate = -1
    adaptation_iteration = 1
    last_burst_rates = []
    last_JEs = []

    if verbose:
        print "Starting adaptation phase..."

    while abs(burst_rate - burstrate_target) > burstrate_tol:

        if (len(last_burst_rates) < 2
                or last_burst_rates[-1] == last_burst_rates[-2]):

            if len(last_burst_rates) > 0:
                if verbose:
                    print 'Auto-burst stage II. - changing weight by 10%'
                if burst_rate > burstrate_target:
                    weight *= 0.9
                else:
                    weight *= 1.1
            else:
                if verbose:
                    print 'Auto-burst stage I. - initial run'
        else:
            if verbose:
                print 'Auto-burst stage III. - linear extrapolation'
            weight = (((burstrate_target - last_burst_rates[-2])
                       * (last_JEs[-1] - last_JEs[-2])
                       / (last_burst_rates[-1] - last_burst_rates[-2]))
                      + last_JEs[-2])
        assert weight > 0.

        if verbose:
            print "adaptation %i, setting weight to %g ..." % (
                adaptation_iteration, weight)
            print 'Setting up network...'
        ncells, ncons, neuronsE, espikes, noise, GIDoffset = create_network(
            network_obj, weight, noise_weight, noise_rate,
            resolution=resolution, verbose=verbose, print_time=print_time,
        )
        if verbose:
            print 'Simulating...'
        nest.Simulate(simtime)
        if verbose:
            print 'Calculating the burst rate...'
        spike_times = nest.GetStatus(espikes, "events")[0]["times"]
        burst_rate = determine_burst_rate(spike_times, simtime, ncells)
        if verbose:
            print "-> the burst rate is %g Hz" % burst_rate
        adaptation_iteration += 1
        last_burst_rates.append(burst_rate)
        last_JEs.append(weight)
        assert adaptation_iteration < maxiter_adapt

    return weight, burst_rate