From d56a2ba39db1a00abdb595faa68d90973409b0d5 Mon Sep 17 00:00:00 2001 From: Michael Hines Date: Wed, 3 Feb 2021 17:00:43 -0500 Subject: [PATCH 1/2] Example of how to write data files as series of submodels. --- ring.py | 2 +- ringtest.py | 22 ++++++++----- test_submodel.py | 85 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 test_submodel.py diff --git a/ring.py b/ring.py index f2071ff..5571b0e 100644 --- a/ring.py +++ b/ring.py @@ -47,7 +47,7 @@ def mkcells(self, ncell, nbranch, ncompart, types): secpar, segvec = celltypeinfo(type, nbranch, ncompart) cell = h.B_BallStick(secpar, segvec) self.cells.append(cell) - settings.pc.set_gid2node(gid, settings.rank) + settings.pc.set_gid2node(gid, settings.pc.id()) nc = cell.connect2target(None) settings.pc.cell(gid, nc) diff --git a/ringtest.py b/ringtest.py index 0c87f5d..02eecf6 100644 --- a/ringtest.py +++ b/ringtest.py @@ -118,20 +118,16 @@ def prun(tstop): return runtime, load_balance, avg_comp_time, spk_time, gap_time -if __name__ == '__main__': - - ## Create all rings ## - - timeit(None, settings.rank) - +def network(): # create network / ring of cells ran = h.Random() ran.Random123(0, 1) types = shuffle([i % ntype for i in range(ncell * nring)], ran) rings = [Ring(ncell, nbranch, ncompart, i * ncell, types) for i in range(nring)] - timeit("created rings", settings.rank) + return rings +def randomize(rings): # randomize parameters if asked if randomize_parameters: from ranparm import cellran @@ -139,8 +135,18 @@ def prun(tstop): for gid in ring.gids: if pc.gid_exists(gid): cellran(gid, ring.nclist) - timeit("randomized parameters", settings.rank) +if __name__ == '__main__': + + ## Create all rings ## + + timeit(None, settings.rank) + + rings = network() + timeit("created rings", settings.rank) + if randomize_parameters: + randomize(rings) + timeit("randomized parameters", settings.rank) ## CoreNEURON setting ## diff --git a/test_submodel.py b/test_submodel.py new file mode 100644 index 0000000..88e2550 --- /dev/null +++ b/test_submodel.py @@ -0,0 +1,85 @@ +# Example of how to construct a model as a series of submodels. Each +# submodel is built, CoreNEURON data is written, and the submodel +# is destroyed. This file can be run with +# python test_submodel.py -rparm +# which writes data to the coredat folder. That folder can be compared to +# the corenrn_data folder written by +# mpiexec -n 4 nrniv -python -mpi -rparm -coreneuron -filemode ringtest.py +# diff -r coredat corenrn_data +# Note: -rparm is used for a more substantive test in that all the cells are +# distinct with differt parameters. + +# The overall strategy for a ringtest model relies on the fact that it is +# already does parallel setup so that there are pc.nhost() submodels, +# one built on each rank, pc.id(). This setup did not use pc.nhost() or +# pc.id() directly but stored those values in the global variables nhost and +# rank respectively. So it is an easy matter to subvert that slightly and +# run with a single process and iterate over range(nsubmodel) and for each +# merely set rank and nhost to the proper values. The one exception to this +# in the ringtest setup was the call to pc.set_gid2node(gid, rank) which was +# changed to pc.set_gid2node(gid, pc.id()) since that function requires the +# true rank of this process to function correctly. The other ringtest +# transformation that was required was to factor out the ring build and +# randomization into functions that are callable from here as well as in +# the original ringtest.py . + +from neuron import h +pc = h.ParallelContext() +cvode = h.CVode() + +import ringtest + +def test_submodel(nsubmodel): + coredat = "./coredat" + cvode.cache_efficient(1) + gidgroups = [h.Vector() for _ in range(nsubmodel)] # used to write files.dat at end + for isubmodel in range(nsubmodel): + submodel = build_submodel(isubmodel, nsubmodel) # just like a single rank on an nhost cluster + pc.nrnbbcore_write("./coredat", gidgroups[isubmodel]) + teardown() + submodel = None + + # verify no netcons or sections. Ready to go on to next submodel + assert (h.List("NetCon").count() == 0) + assert (len([s for s in h.allsec()]) == 0) + + write_files_dat(coredat, gidgroups) + +def build_submodel(isubmodel, nsubmodel): + # fake nhost and rank + ringtest.settings.nhost = nsubmodel + ringtest.settings.rank = isubmodel + + # broke into two parts to avoid timeit problems. + rings= ringtest.network() + ringtest.randomize(rings) + + # same initialization as ringtest + pc.set_maxstep(10) + h.stdinit() + + return rings + +def teardown(): + pc.gid_clear() + # delete your NetCons list + # delete your Cells list + # unfortunately, cannot delete submodel here as there is reference to it + # in test_submodel(nsubmodel) + +# write out the files.dat file +def write_files_dat(coredat, gidgroups): + f = open(coredat+"/files.dat", "w") + f.write("1.4\n") # CoreNEURON data version + + ng = sum(len(g) for g in gidgroups) + f.write(str(ng) + '\n') # number of groups + + for gidgroup in gidgroups: + for x in gidgroup: + f.write(str(int(x)) + '\n') # group id + + f.close() + +if __name__ == "__main__": + test_submodel(4) From 015d6c12723d44886d9fcf8868f6d0bea7b58d42 Mon Sep 17 00:00:00 2001 From: Michael Hines Date: Sun, 7 Feb 2021 17:13:38 -0500 Subject: [PATCH 2/2] Much simplified by using the latest pc.nrncore_write(path, append). --- test_submodel.py | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/test_submodel.py b/test_submodel.py index 88e2550..16771d0 100644 --- a/test_submodel.py +++ b/test_submodel.py @@ -7,9 +7,9 @@ # mpiexec -n 4 nrniv -python -mpi -rparm -coreneuron -filemode ringtest.py # diff -r coredat corenrn_data # Note: -rparm is used for a more substantive test in that all the cells are -# distinct with differt parameters. +# distinct with different parameters. -# The overall strategy for a ringtest model relies on the fact that it is +# The overall strategy for a ringtest model relies on the fact that it # already does parallel setup so that there are pc.nhost() submodels, # one built on each rank, pc.id(). This setup did not use pc.nhost() or # pc.id() directly but stored those values in the global variables nhost and @@ -32,10 +32,11 @@ def test_submodel(nsubmodel): coredat = "./coredat" cvode.cache_efficient(1) - gidgroups = [h.Vector() for _ in range(nsubmodel)] # used to write files.dat at end for isubmodel in range(nsubmodel): submodel = build_submodel(isubmodel, nsubmodel) # just like a single rank on an nhost cluster - pc.nrnbbcore_write("./coredat", gidgroups[isubmodel]) + # second arg below when False, means to begin a new files.dat file. + # when True, means to append the groupid information to the existing file. + pc.nrncore_write("./coredat", isubmodel != 0) teardown() submodel = None @@ -43,8 +44,6 @@ def test_submodel(nsubmodel): assert (h.List("NetCon").count() == 0) assert (len([s for s in h.allsec()]) == 0) - write_files_dat(coredat, gidgroups) - def build_submodel(isubmodel, nsubmodel): # fake nhost and rank ringtest.settings.nhost = nsubmodel @@ -67,19 +66,5 @@ def teardown(): # unfortunately, cannot delete submodel here as there is reference to it # in test_submodel(nsubmodel) -# write out the files.dat file -def write_files_dat(coredat, gidgroups): - f = open(coredat+"/files.dat", "w") - f.write("1.4\n") # CoreNEURON data version - - ng = sum(len(g) for g in gidgroups) - f.write(str(ng) + '\n') # number of groups - - for gidgroup in gidgroups: - for x in gidgroup: - f.write(str(int(x)) + '\n') # group id - - f.close() - if __name__ == "__main__": test_submodel(4)