{load_file("autoThresholdMap.hoc")}

objref attDv[36]
attTotalCells = 0


/////////////////////////////////////////////////////////////////////

// Tiled version of spike detector
func hasSpike() { local idx, i, hyp  // parameter: cell ID to check
    idx = $1
    //index of 1st threshold crossing
    for i = (del+dur*2+0.5)/dt,(del+35)/dt {
        if (attDv[idx].x[i] >= 0) {
            return i
        }
    }
    //excessive stim causes transient hyp after stimulus
    hyp = 1
    for i = (del+dur*2+1.0)/dt,(del+dur*2+4.0)/dt {
        if (attDv[idx].x[i] >= attDv[idx].x[0]) {
            hyp = 0
            break
        }
    }
    if (hyp) { return -1 }
    
    return 0
}

// Tally the ID of cell(s) that spiked in the tile, a -ve return value indicates
// over-stim occured.
func countActivity() { local actvCells, overStimMark, c, latency
    actvCells = 0
    overStimMark = 1
    for c = 0,attTotalCells-1 {
        latency = hasSpike(c)
        if (latency < 0) {
            overStimMark = -1   // -ve multiplier to note overstim
        } else if (latency > 0) {
            actvCells += 2^c    // actvCells uses 1-based cell ID
        }
    }
    return overStimMark * actvCells
}

// Re-implement original procedure for cell tile
func findThresholdInRange() { local xPos, yPos, aMin, aMax, actvCells
    xPos = $1
    yPos = $2
    aMin = $3
    aMax = $4
    setelec(xPos, yPos, stimZ)

    while (aMax - aMin > rangingResolution) {
        stimAmp = (aMax+aMin)/2 * -0.001
        setstim(stimDel, stimDur, stimAmp)
        
        run()
        actvCells = countActivity()
        // print "> ", stimAmp, " ", actvCells
        if (actvCells < 0) {
            return actvCells          //excessive stim
        } else if (actvCells > 0) {
            aMax = (aMax+aMin)/2      //over-stim
        } else {
            aMin = (aMax+aMin)/2      //under-stim
        }
    }
    if (actvCells == 0) {
        // re-run if last did not spike
        stimAmp = aMax * -0.001
        setstim(stimDel, stimDur, stimAmp)
        run()
        actvCells = countActivity()
    }
    return actvCells
}

// Re-implement original procedure for cell tile
proc findThreshold() { local id, aMin, aMax, firstRun, actvCells
    xPos = $1
    yPos = $2
    aMax = STIM_AMP_MAX
    aMin = STIM_AMP_MIN
    overStimLoop = 0
    while (overStimLoop < 3) {
        actvCells = findThresholdInRange(xPos, yPos, aMin, aMax)
        if (actvCells >= 0) {
            break
        }
        aMax = aMax / 2
        overStimLoop += 1
        // print "> overstim ", actvCells
    }
    
    printf("%d %d %.5f %d\n", $1, $2, stimAmp, actvCells)
    if (pc.nhost == 1) {
        aFile.printf("%d %d %.5f %d\n", $1, $2, stimAmp, actvCells)
        aFile.flush()
    } else {
        id = hoc_ac_
        pc.post(id, $1, $2, stimAmp, actvCells)
    }
}

// Re-implement original procedure for cell tile
proc runRegion() { local id, xpos, ypos, amp, actvCells
    if (pc.nhost == 1) {
        // sequential execution
        for aX = $1,$2 {
            for aY = $3,$4 {
                findThreshold(aX * 10, aY * 10)
            }
        }
    } else {
        // parallel execution
        printf("INFO: ParallelContext.host = %d\n", pc.nhost)
        pc.runworker()
        for aX = $1,$2 {
            for aY = $3,$4 {
                pc.submit("findThreshold", aX * 10, aY * 10)
            }
        }
        while ((id = pc.working) != 0) {
            pc.take(id, &xpos, &ypos, &amp, &actvCells)
            aFile.printf("%d %d %.5f %d\n", xpos, ypos, amp, actvCells)
            aFile.flush()
        }
        pc.done
    }
}


/////////////////////////////////////////////////////////////////////

// Initialization for off cell tile
proc atmInitOffCells() { local c
    for c = 0,offCells-1 {
        attDv[c] = new Vector()
        attDv[c].record(&off[c].soma.v(0.5))
    }
    attTotalCells += offCells
}

// Initialization for on cell tile
proc atmInitOnCells() { local c
    for c = 0,onCells-1 {
        attDv[c] = new Vector()
        attDv[c].record(&on[c].soma.v(0.5))
    }
    attTotalCells += onCells
}