def setupLayerPN(params, neuronModel, cell_params, populationsRN, populationsPN):

    # create a projection neuron PN cluster population per VR
    # this will be fed by the equivalent RN population and will laterally
    # inhibit between clusters

    numVR = int(params["NUM_VR"])
    # print 'PN layer, no. VR: ' , numVR
    pnClusterSize = int(params["CLUSTER_SIZE"] * params["NETWORK_SCALE"])
    maxNeuronsPerCore = int(params["MAX_NEURONS_PER_CORE"])

    maxVrPerPop = maxNeuronsPerCore / pnClusterSize

    # how many cores were needed to accomodate RN layer (1 pynn pop in this case)
    numCoresRN = utils.coresRequired(populationsRN, maxNeuronsPerCore)
    # print 'The RN layer is taking up ', numCoresRN, ' cores'

    coresAvailablePN = int(
        params["CORES_ON_BOARD"] - params["NUM_CLASSES"] - numCoresRN - 3
    )  # 2 x input, 1 x noise source
    # print 'PN layer, no. cores available:' , coresAvailablePN

    vrPerPop = int(ceil(float(numVR) / float(coresAvailablePN)))
    if vrPerPop > maxVrPerPop:
        print "The number of VR and/or cluster size stipulated for \
                this model are too a large for the capacity of this board."
        quit

    # print 'PN layer, no. VRs per population will be: ', vrPerPop
    pnPopSize = pnClusterSize * vrPerPop
    # print 'PN layer, neurons per population will be: ', pnPopSize
    numPopPN = int(ceil(float(numVR) / float(vrPerPop)))
    # print 'PN layer, number of populations(cores) used will be: ', numPopPN
    # print 'PN layer, spare (unused) cores : ', coresAvailablePN - numPopPN

    weightPNPN = float(params["WEIGHT_WTA_PN_PN"])
    delayPNPN = int(params["DELAY_WTA_PN_PN"])
    connectivityPNPN = float(params["CONNECTIVITY_WTA_PN_PN"])

    for p in range(numPopPN):
        popName = "popPN_" + str(p)
        popPN = spynnaker.Population(pnPopSize, neuronModel, cell_params, label=popName)
        # print 'created population ', popName
        populationsPN.append(popPN)

        # create a FromList to feed each PN neuron in this popn from its
        # corresponding RN neuron in the single monolithic RN popn
        weightRNPN = float(params["WEIGHT_RN_PN"])
        delayRNPN = int(params["DELAY_RN_PN"])
        rnStartIdx = p * pnPopSize
        rnEndIdx = rnStartIdx + pnPopSize - 1

        # The last PN popn will often have unneeded 'ghost' clusters at
        # the end due to imperfect dstribution of VRs among cores
        # As there is no RN cluster that feeds these (RN is one pop of the
        # correct total size) so the connections must stop at the end of RN

        rnMaxIdx = populationsRN[0]._size - 1
        if rnEndIdx > rnMaxIdx:
            rnEndIdx = rnMaxIdx  # clamp to the end of the RN population

        pnEndIdx = rnEndIdx - rnStartIdx

        connections = utils.fromList_OneToOne_fromRangeToRange(
            rnStartIdx, rnEndIdx, 0, pnEndIdx, weightRNPN, delayRNPN, delayRNPN
        )
        projClusterRNToClusterPN = spynnaker.Projection(
            populationsRN[0], popPN, spynnaker.FromListConnector(connections), target="excitatory"
        )

        # within this popn only, connect each PN sub-population VR
        # "cluster" to inhibit every other
        if vrPerPop > 1:
            utils.createIntraPopulationWTA(popPN, vrPerPop, weightPNPN, delayPNPN, connectivityPNPN, True)

    # Also connect each PN cluster to inhibit every other cluster
    utils.createInterPopulationWTA(populationsPN, weightPNPN, delayPNPN, connectivityPNPN)
def setupLayerPN(params, neuronModel, cell_params, populationsRN,
                 populationsPN):

    #create a projection neuron PN cluster population per VR
    #this will be fed by the equivalent RN population and will laterally
    #inhibit between clusters

    numVR = int(params['NUM_VR'])
    #print 'PN layer, no. VR: ' , numVR
    pnClusterSize = int(params['CLUSTER_SIZE'] * params['NETWORK_SCALE'])
    maxNeuronsPerCore = int(params['MAX_NEURONS_PER_CORE'])

    maxVrPerPop = maxNeuronsPerCore / pnClusterSize

    #how many cores were needed to accomodate RN layer (1 pynn pop in this case)
    numCoresRN = utils.coresRequired(populationsRN, maxNeuronsPerCore)
    #print 'The RN layer is taking up ', numCoresRN, ' cores'

    coresAvailablePN = int(params['CORES_ON_BOARD'] - params['NUM_CLASSES'] -
                           numCoresRN - 3)  # 2 x input, 1 x noise source
    #print 'PN layer, no. cores available:' , coresAvailablePN

    vrPerPop = int(ceil(float(numVR) / float(coresAvailablePN)))
    if vrPerPop > maxVrPerPop:
        print 'The number of VR and/or cluster size stipulated for \
                this model are too a large for the capacity of this board.'

        quit

    #print 'PN layer, no. VRs per population will be: ', vrPerPop
    pnPopSize = pnClusterSize * vrPerPop
    #print 'PN layer, neurons per population will be: ', pnPopSize
    numPopPN = int(ceil(float(numVR) / float(vrPerPop)))
    #print 'PN layer, number of populations(cores) used will be: ', numPopPN
    #print 'PN layer, spare (unused) cores : ', coresAvailablePN - numPopPN

    weightPNPN = float(params['WEIGHT_WTA_PN_PN'])
    delayPNPN = int(params['DELAY_WTA_PN_PN'])
    connectivityPNPN = float(params['CONNECTIVITY_WTA_PN_PN'])

    for p in range(numPopPN):
        popName = 'popPN_' + str(p)
        popPN = spynnaker.Population(pnPopSize,
                                     neuronModel,
                                     cell_params,
                                     label=popName)
        #print 'created population ', popName
        populationsPN.append(popPN)

        #create a FromList to feed each PN neuron in this popn from its
        #corresponding RN neuron in the single monolithic RN popn
        weightRNPN = float(params['WEIGHT_RN_PN'])
        delayRNPN = int(params['DELAY_RN_PN'])
        rnStartIdx = p * pnPopSize
        rnEndIdx = rnStartIdx + pnPopSize - 1

        # The last PN popn will often have unneeded 'ghost' clusters at
        #the end due to imperfect dstribution of VRs among cores
        # As there is no RN cluster that feeds these (RN is one pop of the
        #correct total size) so the connections must stop at the end of RN

        rnMaxIdx = populationsRN[0]._size - 1
        if rnEndIdx > rnMaxIdx:
            rnEndIdx = rnMaxIdx  #clamp to the end of the RN population

        pnEndIdx = rnEndIdx - rnStartIdx

        connections = utils.fromList_OneToOne_fromRangeToRange(
            rnStartIdx, rnEndIdx, 0, pnEndIdx, weightRNPN, delayRNPN,
            delayRNPN)
        projClusterRNToClusterPN = spynnaker.Projection(
            populationsRN[0],
            popPN,
            spynnaker.FromListConnector(connections),
            target='excitatory')

        #within this popn only, connect each PN sub-population VR
        #"cluster" to inhibit every other
        if vrPerPop > 1:
            utils.createIntraPopulationWTA(popPN, vrPerPop, weightPNPN,
                                           delayPNPN, connectivityPNPN, True)

    #Also connect each PN cluster to inhibit every other cluster
    utils.createInterPopulationWTA(populationsPN, weightPNPN, delayPNPN,
                                   connectivityPNPN)