Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BBPBGLIB-1122] Removing legacy RNGs, leaving only Random123 #136

Merged
merged 6 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
41 changes: 10 additions & 31 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"""
seed = kw.get("seed")
return Neuron.h.Random() if seed is None else Neuron.h.Random(seed)
def __new__(cls, **kw):
"""Creates a default RNG (Random123 with ids of 0,1,2)"""
seed = kw.get("seed", 0)
return Random123(0, 1, 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
150 changes: 6 additions & 144 deletions neurodamus/data/hoc/RNGSettings.hoc
atemerev marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/
{load_file("fileUtils.hoc")}

rngMode = 0 // corresponds to COMPATIBILITY defined below
rngMode = 1 // corresponds to RANDOM123 defined below
ionchannelSeed = 0
synapseSeed = 0
stimulusSeed = 0
Expand All @@ -17,15 +17,13 @@ globalSeed = 0
begintemplate RNGSettings

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

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

proc init() {
// consts for random number handling
COMPATIBILITY = 0
RANDOM123 = 1
atemerev marked this conversation as resolved.
Show resolved Hide resolved
UPMCELLRAN4 = 2
}

/**
Expand All @@ -50,40 +48,21 @@ proc interpret() { local coreNeuronUsed localobj runInfo, pc, rng

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 ) {
if( strcmp( rngModeField, "Random123" ) == 0 ) {
rngMode = RANDOM123
} else {
terminate( "Invalid RNGMode ", rngModeField )
terminate( "Invalid RNGMode (only Random123 is currently supported) ", 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 Down Expand Up @@ -123,120 +102,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
}
}
}
10 changes: 3 additions & 7 deletions neurodamus/stimulus_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,15 +561,11 @@ def __init__(self, target, stim_info: dict, cell_manager):
self.parse_check_all_parameters(stim_info)

sim_dt = float(SimConfig.run_conf["Dt"]) # simulation time-step [ms]
rng_mode = SimConfig.rng_info.getRNGMode() # simulation RNGMode

# setup RNG
if rng_mode == SimConfig.rng_info.RANDOM123:
rand = lambda gid: random.Random123(Noise.stimCount + 100,
SimConfig.rng_info.getStimulusSeed() + 500,
gid + 300)
else:
raise Exception("rng_mod is not RANDOM123")
rand = lambda gid: random.Random123(Noise.stimCount + 100,
SimConfig.rng_info.getStimulusSeed() + 500,
gid + 300)

# apply stim to each point in target
tpoints = target.getPointList(cell_manager)
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/test_neuron.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ def test_base_h():
def neurodamus():
from neurodamus.core import NeurodamusCore as Nd
rng_conf = Nd.RNGSettings()
assert rng_conf.RANDOM123 == 1
assert rng_conf.getGlobalSeed() == 0
Loading