1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
|
.. _bbsavestate:
BBSaveState
-----------
.. class:: BBSaveState
A more flexible, cell centered version of :class:`SaveState`
The goal is to be able to save state to a file and restore state when the
save and restore contexts have different numbers of processors, different
distribution of gids, and different splitting. It needs to work efficiently
in the context of many GByte file sizes and many thousands of processors.
The class was originally developed with the needs of the BlueBrain
neocortical model in mind.
The following code fragment illustrates a basic test. When 'restore'
is False, the simulation run stops half way and saves the state and then
continues. When 'restore' is True, the simulation begins at the previous
save time and continues to tstop.
.. code-block::
python
def prun(tstop, restore=False):
pc.set_maxstep(10)
h.stdinit()
bbss = h.BBSaveState()
if restore:
bbss.restore_test()
print('after restore t=%g' % h.t)
else:
pc.psolve(tstop/2)
bbss.save_test()
pc.psolve(tstop)
Note that files are saved in a subdirectory called "out" and restored
from a subdirectory called "in". An empty "out" folder should be created by
the user prior to calling save_test(). A script filter
(see :meth:`BBSaveState.save_test`) is needed to copy and sometimes
concatenate files from the out to the in subfolders. These files have
an ascii format.
BBSaveState has a c++ API that allows one to replace the file reader and
writer. See `nrn/src/nrniv/bbsavestate.cpp <https://github.com/neuronsimulator/nrn/blob/master/src/nrniv/bbsavestate.cpp>`_
for a description of this API.
The undocumented methods, ``save_test_bin`` and ``restore_test_bin`` demonstrate
the use of this API.
The user can mark a point process IGNORE by calling the method
bbss.ignore(point_process_object)
on all the point processes to be ignored.
The internal list of ignored point processes can be cleared by calling
bbss.ignore()
Because a restore clears the event queue and because one cannot call
finitialize from hoc without vitiating the restore, :meth:`Vector.play` will
not work unless one calls :meth:`BBSaveState.vector_play_init` after a
restore (similarly :func:`frecord` must be called for :meth:`Vector.record` to work.
Note that it is necessary that Vector.play use a tvec argument with
a first element greater than or equal to the restore time.
Some model restrictions:
1. "Real" cells must have gids.
2. Artificial cells can have gids. If not they must be directly connected
to just one synapse (e.g. NetStim -> NetCon -> synapse).
3. There is only one spike output port per cell and that is associated
with a base gid.
4. NetCon.event in Hoc can be used only with NetCon's with a None source.
To allow extra state, such as Random sequence, to be saved for
POINT_PROCESS or SUFFIX density nmodl mechanisms,
declare FUNCTION bbsavestate() within the mechanism.
That function is called when the
mechanism instance is saved and restored.
FUNCTION bbsavestate takes two pointers to double arrays
xdir and xval.
The first double array, xdir, has length 1 and xdir[0] is -1.0, 0.0, or 1.0
If xdir[0] == -1.0, then replace the xdir[0] with the proper number of elements
of xval and return 0.0. If xdir[0] == 0.0, then save double values into
the xval array (which will be sized correctly from a previous call with
xdir[0] == -1.0). If xdir[0] == 1.0, then the saved double values are in
xval and should be restored to their original values.
The number of elements saved/restored has to be apriori known by the instance
since the size of the xval that was saved is not sent to the instance on
restore.
For example
.. code-block::
C++
FUNCTION bbsavestate() {
bbsavestate = 0
VERBATIM
double *xdir, *xval, *hoc_pgetarg();
xdir = hoc_pgetarg(1);
if (*xdir == -1.) { *xdir = 2; return 0.0; }
xval = hoc_pgetarg(2);
if (*xdir == 0.) { xval[0] = 20.; xval[1] = 21.;}
if (*xdir == 1) { printf("%d %d\n", xval[0]==20.0, xval[1] == 21.0); }
ENDVERBATIM
}
----
.. method:: BBSaveState.save_test
Syntax:
``.save_test()``
Description:
State of the model is saved in files within the subdirectory, `out`.
The file `out/tmp` contains the value of t. Other files have the
filename format tmp.<gid>.<rank> . Only in the case of multisplit
is it possible to have the same gid in more than one filename. Note
that the out folder needs to be created by the user prior to a call
to save_test().
To prepare for a restore, the tmp.<gid>.<rank> files should be copied
from the `out` subfolder to a subfolder called `in`, with the filename
in/tmp.<gid> . Each file should begin with a first line that specifies
the number of files in the `out` folder that had the same gid.
The following out2in.sh script shows how to do this (not particularly
efficiently).
.. code-block::
bash
#!/usr/bin/env bash
rm -f in/*
cat out/tmp > in/tmp
for f in out/tmp.*.* ; do
echo $f
i=`echo "$f" | sed 's/.*tmp\.\([0-9]*\)\..*/\1/'`
echo $i
if test ! -f in/tmp.$i ; then
cnt=`ls out/tmp.$i.* | wc -l`
echo $cnt > in/tmp.$i
cat out/tmp.$i.* >> in/tmp.$i
fi
done
----
.. method:: BBSaveState.restore_test
Syntax:
``.restore_test()``
Description:
State of the model is restored from files within the
subdirectory, "in". The file "in/tmp" supplies the value of t.
Other files have the filename format tmp.<gid> and are read when
that gid is restored. Note that in a multisplit context, the same
"in/tmp.<gid>" file will be read by multiple ranks, but only the state
assocated with sections that exist on a rank will be restored.
----
.. method:: BBSaveState.ignore
Syntax:
``.ignore(ppobj)``
Description:
Point processes can be marked IGNORE
which will skip them on save/restore.
The internal list of these ignored point processes must be the same
on save and restore.
----
.. method:: BBSaveState.vector_play_init
Syntax:
``.vector_play_init()``
Description:
Allow :meth:`Vector.play` to work. Call this method after a restore
if there are any Vector.play in the model.
|