Skip to content

Commit

Permalink
All RNG usages except Random123 are removed. All non-Random123 config…
Browse files Browse the repository at this point in the history
…uration options removed
  • Loading branch information
atemerev committed Feb 29, 2024
1 parent c4a87c1 commit 9a1796d
Show file tree
Hide file tree
Showing 10 changed files with 33 additions and 292 deletions.
164 changes: 4 additions & 160 deletions core/hoc/RNGSettings.hoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
*/
{load_file("fileUtils.hoc")}

rngMode = 0 // corresponds to COMPATIBILITY defined below
ionchannelSeed = 0
synapseSeed = 0
stimulusSeed = 0
Expand All @@ -16,16 +15,11 @@ globalSeed = 0

begintemplate RNGSettings

public init, interpret, getRNGMode, getIonChannelSeed, getSynapseSeed, getStimulusSeed, getMinisSeed, getGlobalSeed
public COMPATIBILITY, RANDOM123, UPMCELLRAN4
public init, interpret, getIonChannelSeed, getSynapseSeed, getStimulusSeed, getMinisSeed, getGlobalSeed

external rngMode, ionchannelSeed, synapseSeed, stimulusSeed, minisSeed, globalSeed, terminate
external ionchannelSeed, synapseSeed, stimulusSeed, minisSeed, globalSeed, terminate

proc init() {
// consts for random number handling
COMPATIBILITY = 0
RANDOM123 = 1
UPMCELLRAN4 = 2
}

/**
Expand All @@ -37,7 +31,6 @@ proc init() {
proc interpret() { local coreNeuronUsed localobj runInfo, pc, rng
strdef rngModeField
runInfo = $o1
rngMode = RANDOM123
coreNeuronUsed = $2
if (numarg() < 2) {
coreNeuronUsed = 0
Expand All @@ -48,42 +41,14 @@ proc interpret() { local coreNeuronUsed localobj runInfo, pc, rng
print "As of Oct 2020 Neurodamus uses Random123 as default"
}

if( runInfo.exists( "RNGMode" ) ) {
rngModeField = runInfo.get( "RNGMode" ).s
if( strcmp( rngModeField, "Compatibility" ) == 0 ) {
rngMode = COMPATIBILITY
} else if( strcmp( rngModeField, "UpdatedMCell" ) == 0 ) {
rngMode = UPMCELLRAN4
} else if( strcmp( rngModeField, "Random123" ) == 0 ) {
rngMode = RANDOM123
} else {
terminate( "Invalid RNGMode ", rngModeField )
}
if( pc.id() == 0 ) {
print "RNGMode set to ", rngMode, " [COMPATIBILITY=0, RANDOM123=1, UPMCELLRAN4=2]"
}
}

if( coreNeuronUsed && rngMode != RANDOM123) {
// Given R123 is now the default there's no sense to allow an explicit invalid option
terminate( "Config Error: CoreNEURON requires Random123 RNG" )
}

if( runInfo.exists("BaseSeed") ) {
globalSeed = runInfo.valueOf( "BaseSeed" )

// random123 can set the global index now
if( rngMode == RANDOM123 ) {
rng = new Random()
rng.Random123_globalindex( globalSeed )
}
rng = new Random()
rng.Random123_globalindex( globalSeed )
}

// don't search for indicidual seeds if we are in compatibility mode
if( rngMode == COMPATIBILITY ) {
return
}

if( runInfo.exists("IonChannelSeed") ) {
ionchannelSeed = runInfo.valueOf( "IonChannelSeed" )
}
Expand All @@ -98,10 +63,6 @@ proc interpret() { local coreNeuronUsed localobj runInfo, pc, rng
}
}

func getRNGMode() {
return rngMode
}

func getIonChannelSeed() {
return ionchannelSeed
}
Expand All @@ -123,120 +84,3 @@ func getGlobalSeed() {
}

endtemplate RNGSettings


///////////////////////////////////////////////////////////////////////
///
/// These are legacy functions to keep compaltibility
///
///////////////////////////////////////////////////////////////////////

/*!
* In place of using a CCell's re_init_rng function, we will check for cells that define the re_init_rng function,
* but then setRNG using global seed as well
*
* @param $o1 CCell which is to be checked for setRNG
*/
obfunc rngForStochKvInit() { local channelID, hasStochKv localobj CCell, rng, rngInfo, rngList, pc
CCell = $o1
//print "Replace rng for stochKv in gid ", CCell.CellRef.gid

// quick check to verify this object contains StochKv
hasStochKv = 0
CCell.CellRef.soma {
if( ismembrane( "StochKv" ) ) {
hasStochKv = 1
}
}

if( !hasStochKv ) {
return
}

rngList = new List()

channelID = 0
forsec CCell.CellRef.somatic {
for (x, 0) {
setdata_StochKv(x)
rng = new Random()
rng.MCellRan4( channelID*10000+100, globalSeed + ionchannelSeed + CCell.CellRef.gid*10000+250+1 )
channelID = channelID + 1
rng.uniform(0,1)
setRNG_StochKv(rng)
rngList.append(rng)
}
}
forsec CCell.CellRef.basal {
for (x, 0) {
setdata_StochKv(x)
rng = new Random()
rng.MCellRan4( channelID*10000+100, globalSeed + ionchannelSeed + CCell.CellRef.gid*10000+250+1 )
channelID = channelID + 1
rng.uniform(0,1)
setRNG_StochKv(rng)
rngList.append(rng)
}
}
forsec CCell.CellRef.apical {
for (x, 0) {
setdata_StochKv(x)
rng = new Random()
rng.MCellRan4( channelID*10000+100, globalSeed + ionchannelSeed + CCell.CellRef.gid*10000+250+1 )
channelID = channelID + 1
rng.uniform(0,1)
setRNG_StochKv(rng)
rngList.append(rng)
}
}

return rngList
}

//-----------------------------------------------------------------------------------------------

/*!
* In place of using a CCell's re_init_rng function, we will check for cells that define the re_init_rng function,
* but then setRNG using random123
*
* @param $o1 CCell which is to be checked for setRNG
*/
proc rng123ForStochKvInit() { local channelID, hasStochKv localobj CCell
CCell = $o1
//print "Replace rng for stochKv in gid ", CCell.CellRef.gid

// quick check to verify this object contains StochKv
hasStochKv = 0
CCell.CellRef.soma {
if( ismembrane( "StochKv" ) ) {
hasStochKv = 1
}
}

if( !hasStochKv ) {
return
}

channelID = 0
forsec CCell.CellRef.somatic {
for (x, 0) {
setdata_StochKv(x)
setRNG_StochKv(ionchannelSeed, channelID, CCell.CellRef.gid + 1)
channelID = channelID + 1
}
}
forsec CCell.CellRef.basal {
for (x, 0) {
setdata_StochKv(x)
setRNG_StochKv(ionchannelSeed, channelID, CCell.CellRef.gid + 1)
channelID = channelID + 1
}
}
forsec CCell.CellRef.apical {
for (x, 0) {
setdata_StochKv(x)
setRNG_StochKv(ionchannelSeed, channelID, CCell.CellRef.gid + 1)
channelID = channelID + 1
}
}
}
23 changes: 4 additions & 19 deletions core/hoc/StimulusManager.hoc
Original file line number Diff line number Diff line change
Expand Up @@ -423,16 +423,8 @@ proc relativeNoise() { local x, threshold localobj pts, cellList, rand, tstim,
for cellIndex=0, pts.count()-1 {
for pts.o(cellIndex).each_point(&x) {
threshold = cellList.o(cellIndex).getThreshold()

if( rngInfo.getRNGMode() == rngInfo.COMPATIBILITY ) {
rand = new Random( pts.o(cellIndex).gid + noiseStimCount )
} else if( rngInfo.getRNGMode() == rngInfo.UPMCELLRAN4 ) {
rand = new Random()
rand.MCellRan4( noiseStimCount*10000+100, rngInfo.getGlobalSeed() + rngInfo.getStimulusSeed() + pts.o(cellIndex).gid*1000 )
} else if( rngInfo.getRNGMode() == rngInfo.RANDOM123 ) {
rand = new Random()
rand.Random123( noiseStimCount+100, rngInfo.getStimulusSeed() + 500, pts.o(cellIndex).gid + 300 )
}
rand = new Random()
rand.Random123( noiseStimCount+100, rngInfo.getStimulusSeed() + 500, pts.o(cellIndex).gid + 300 )
tstim = new TStim(x, rand)
tstim.noise( $4, $5, threshold*$2/100, threshold*$3/100 )
stimList.append(tstim)
Expand Down Expand Up @@ -462,15 +454,8 @@ proc noise() { local x localobj pts, rand, tstim, rngInfo

for cellIndex=0, pts.count()-1 {
for pts.o(cellIndex).each_point(&x) {
if( rngInfo.getRNGMode() == rngInfo.COMPATIBILITY ) {
rand = new Random( pts.o(cellIndex).gid + noiseStimCount )
} else if( rngInfo.getRNGMode() == rngInfo.UPMCELLRAN4 ) {
rand = new Random()
rand.MCellRan4( noiseStimCount*10000+100, rngInfo.getGlobalSeed() + rngInfo.getStimulusSeed() + pts.o(cellIndex).gid*1000 )
} else if( rngInfo.getRNGMode() == rngInfo.RANDOM123 ) {
rand = new Random()
rand.Random123( noiseStimCount+100, rngInfo.getStimulusSeed() + 500, pts.o(cellIndex).gid + 300 )
}
rand = new Random()
rand.Random123( noiseStimCount+100, rngInfo.getStimulusSeed() + 500, pts.o(cellIndex).gid + 300 )
tstim = new TStim(x, rand)
tstim.noise( $4, $5, $2, $3 )
stimList.append(tstim)
Expand Down
10 changes: 3 additions & 7 deletions core/hoc/TStim.hoc
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

D__TSTIMHOC = 1

{load_file("RNGSettings.hoc")}

/**
* TStim class is intended to make it easy to use current injection stimulation.
* it has injection premitives (pulse, ramp, segment, sinspec, noise)
Expand Down Expand Up @@ -167,11 +165,9 @@ begintemplate TStim
rand.normal($3,$4)
tstim_end = $1+$2

rngInfo = new RNGSettings()

// To help with save state, we want Noise stimulus to continue where it left off
// so first draw the numbers that were already used (not very efficient, but can be improved later)
if( rngInfo.getRNGMode() != rngInfo.COMPATIBILITY ) if( $1 > 0 ) {
if( $1 > 0 ) {

// this can use up a lot of memory as simulation times increase. Should do a proper rewrite, but for now
// make sure no chunk is larger than what we will use for the actual simulation
Expand Down Expand Up @@ -199,8 +195,8 @@ begintemplate TStim

// If the stimulus starts with a delay from simulation start time, we will want 0 amps until the next Dt.
// Note that for Resume, we will be at t > 0 and delay was offset by previous save time. Ergo, we must check that delay > t
// Note that for legacy versions, we always start with 0 amps; when we stop support for legacy, we should selectively set initial slot to 0
if( rngInfo.getRNGMode() == rngInfo.COMPATIBILITY || $1 > t ) {

if( $1 > t ) {
stim.x[0] = 0
}

Expand Down
30 changes: 3 additions & 27 deletions neurodamus/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,36 +714,12 @@ def create_on(self, conn, sec, position, syn_obj, syn_params, base_seed, _rate_v
self._store(ips, netcon)

src_pop_id, dst_pop_id = conn.population_id
rng_mode = self._rng_info.getRNGMode()
rng_seed = self._rng_info.getMinisSeed()
tgid_seed = conn.tgid + 250

if rng_mode == self._rng_info.RANDOM123:
seed2 = (src_pop_id * 65536 + dst_pop_id + rng_seed)
ips.setRNGs(syn_obj.synapseID + 200, tgid_seed, seed2 + 300,
syn_obj.synapseID + 200, tgid_seed, seed2 + 350)
else:
seed2 = src_pop_id * 16777216
exprng = Nd.Random()
if rng_mode == self._rng_info.COMPATIBILITY:
exprng.MCellRan4(syn_obj.synapseID * 100000 + 200,
tgid_seed + base_seed + rng_seed)
else: # if ( rngIndo.getRNGMode()== rng_info.UPMCELLRAN4 ):
exprng.MCellRan4(syn_obj.synapseID * 1000 + 200,
seed2 + tgid_seed + base_seed + rng_seed)

exprng.negexp(1)
uniformrng = Nd.Random()
if rng_mode == self._rng_info.COMPATIBILITY:
uniformrng.MCellRan4(syn_obj.synapseID * 100000 + 300,
tgid_seed + base_seed + rng_seed)
else: # if ( rngIndo.getRNGMode()== rng_info.UPMCELLRAN4 ):
uniformrng.MCellRan4(syn_obj.synapseID * 1000 + 300,
seed2 + tgid_seed + base_seed + rng_seed)

uniformrng.uniform(0.0, 1.0)
ips.setRNGs(exprng, uniformrng)
self._keep_alive += (exprng, uniformrng)
seed2 = (src_pop_id * 65536 + dst_pop_id + rng_seed)
ips.setRNGs(syn_obj.synapseID + 200, tgid_seed, seed2 + 300,
syn_obj.synapseID + 200, tgid_seed, seed2 + 350)

def __bool__(self):
"""object is considered False in case rate is not positive"""
Expand Down
2 changes: 0 additions & 2 deletions neurodamus/core/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,6 @@ class CircuitConfig(ConfigT):


class RNGConfig(ConfigT):
Modes = Enum("Mode", "COMPATIBILITY RANDOM123 UPMCELLRAN4")
mode = Modes.COMPATIBILITY
global_seed = None
IonChannelSeed = None
StimulusSeed = None
Expand Down
37 changes: 8 additions & 29 deletions neurodamus/core/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,36 @@
"""
from __future__ import absolute_import
from . import Neuron
from neurodamus.core.configuration import RNGConfig


# NOTE: These are pure wrappers, in the sense they dont create Python objects. Instead
# NOTE: These are pure wrappers, in the sense they don't create Python objects. Instead
# Neuron objects are returned (using __new__)


class RNG(object):
def __new__(cls, *ids, **kw):
"""Creates a default RNG, currently based on ACG"""
"""Creates a default RNG (Random123) """
seed = kw.get("seed")
return Neuron.h.Random() if seed is None else Neuron.h.Random(seed)
return Random123(ids[0], ids[1], ids[2], seed)

@classmethod
def create(cls, rng_mode, ids, seed=None):
# type: (RNGConfig, tuple, object) -> RNG
if rng_mode == RNGConfig.Modes.RANDOM123:
assert len(ids) == 3, "Random123 requires three ids (as a tuple)"
obj = Random123(ids[0], ids[1], ids[2], seed)
elif rng_mode == RNGConfig.Modes.UPMCELLRAN4:
assert len(ids) == 1
obj = MCellRan4(ids[0], seed)
else:
obj = RNG(seed)
def create(cls, ids, seed=None):
# type: (tuple, object) -> RNG
assert len(ids) == 3, "Random123 requires three ids (as a tuple)"
obj = Random123(ids[0], ids[1], ids[2], seed)

return obj


class ACG(RNG):
def __new__(cls, size=None, seed=None):
rng = RNG(seed=seed)
rng.ACG(seed, size)
return rng


class Random123(RNG):
def __new__(cls, id1, id2, id3, seed=None):
rng = RNG()
rng = Neuron.h.Random() if seed is None else Neuron.h.Random(seed)
if seed is not None:
rng.Random123_globalindex(seed)
rng.Random123(id1, id2, id3)
return rng


class MCellRan4(RNG):
def __new__(cls, high_i, seed=None, low_i=0):
rng = RNG(seed=seed)
rng.MCellRan4(high_i, low_i)
return rng


# Gamma-distributed sample generator (not available in NEURON)
def gamma(rng, a, b, N=1):
"""
Expand Down
Loading

0 comments on commit 9a1796d

Please sign in to comment.