How to locate mech var index in the model exported by bbcorewrite? #3441
Replies: 6 comments 10 replies
-
|
I don't understand the context. CoreNEURON generally gets the model and data from NEURON whether CoreNEURON is running in file or direct-memory mode. Thus the value of the 3rd IClamp.amp in CoreNEURON is the same as NEURON's value.when it created the files or copied its data into CoreNEURON. bbcorewrite in a mod file is essentially a helper for this activity for the case of mod files that use Random123 or Vector. In direct memory mode there are functions that map a NEURON reference to a CoreNEURON data location to allow copying of trajectory information gathered during a CoreNEURON run back into NEURON (for Vector.record and Graph trajectories). Also when a direct memory mode CoreNEURON run is complete, all model data (including the event queue) is copied back into NEURON. I'm likely missing your point and it may help to further describe operationally when you need to modify the value of mech_obj.amp in CoreNEURON. For example, if I may be permitted to invent a context, I could say I want to force iclamp.amp t to follow a set of step changes described by a pair of Vectors that describe a step function of amp3 discontinuities at time points. In that case I would get it working first in NEURON using Vector.play |
Beta Was this translation helpful? Give feedback.
-
|
The workflow I'm looking forward to is:
|
Beta Was this translation helpful? Give feedback.
-
|
Oh, I just found that |
Beta Was this translation helpful? Give feedback.
-
|
NEURON version 8.2.x was fully AOS and there had to be a conversion to CoreNEURON SOA. NEURON version 9.0 is now also SOA and each variable name has it's own std::vector container so much less conversion is needed. A mechanism has many variables and thus many std::vector and also an associated permutation vector. All of this container and data handle stuff is implemented in nrn/src/neuron. For simulation we often try to permute so that access to values in each vector is sequential for each time step. Turns out that for multiple threads, we now just permute the vectors so each thread is contiguous. Also, our pointers (data handles) now have the nice property that they always point to the correct value regardless of what permutation is used and whether backing store has been freed and reallocated. I other words, I see another message from you has arrived. I'll stop now and continue after pondering it. |
Beta Was this translation helpful? Give feedback.
-
|
Thank you for your reply. Based on your suggestion, I examined Leveraging this feature, I wrote a wrapper that is compatible with the current mainline NEURON simulator code. By enumerating the Next, using Python's The code I pasted afterward was only intended as a technical demonstration. At this stage, the wrapper only serves to create a backup of the variable. When With slight modifications, this technique can be extended so that accessing wrapper.var actually modifies the corresponding value in the exported model file. import re
class MechWrapper:
def __init__(self, mech):
self.__mech = mech
self.__row_map = {}
self.__backup = {}
self.__allowed_vars = set()
for name in mech.__dict__:
ref_name = f"_ref_{name}"
try:
ref = getattr(mech, ref_name)
match = re.search(r'row=(\d+)/\d+', str(ref))
if match:
row = int(match.group(1))
self.__row_map[name] = row
self.__backup[name] = getattr(mech, name)
self.__allowed_vars.add(name)
self._create_property(name)
except Exception:
continue
def _create_property(self, name):
def getter(self):
print(f"Accessing '{name}' at row {self.__row_map[name]}")
return self.__backup[name]
def setter(self, value):
print(f"Updating backup value of '{name}' to {value}")
self.__backup[name] = value
setattr(self.__class__, name, property(getter, setter))
def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value)
elif name in getattr(self, '__allowed_vars', set()):
object.__setattr__(self, name, value)
else:
raise AttributeError(f"Cannot add new attribute '{name}'")
def __getattr__(self, name):
if name in self.__allowed_vars:
return getattr(self, name)
raise AttributeError(f"Attribute '{name}' not found")
from neuron import h
soma = h.Section()
iclamp = h.IClamp(soma(0.5))
wrapper = MechWrapper(iclamp)
# Accessing a property
print(wrapper.amp) # Prints row info + returns backup value
# Modifying a property
wrapper.amp = 5.0 # Only modifies backup, does not affect NEURON internal value
print(wrapper.amp) # Prints row info + returns updated backup value
print(wrapper.__dict__)
wrapper.not_a_real_var = 42 # Attempt to add a nonexistent variable — should raise error
print(wrapper.not_a_real_var) # Attempt to access nonexistent variable — should raise error |
Beta Was this translation helpful? Give feedback.
-
|
However, this current technique does come with some limitations. Firstly, I discovered that in NEURON, changes to morphology only take full effect after calling Therefore, it's crucial to strictly follow the workflow: # Build NEURON model
iclamp_wrap = wrap_mgr.create_wrapper(neuron_iclamp_obj)
wrap_mgr.dump_model(path) # internally calls bbcorewrite + iclamp_wrap.init() to get correct row value
iclamp_wrap.amp = xx # generate model modification sequence or other operationsThese wrapper classes can then be serialized and deserialized using Python's pickle module, which is convenient for repeated simulation runs. However, one issue is that this approach only supports modifying mechanisms (mech) that were already created during NEURON's modeling phase. It does not support adding new mechanisms after loading the exported model. Additionally, for operations like accessing or modifying voltage values, it is necessary to specify the target location (e.g., In other words, NEURON’s current model export process results in some loss of information. While the use of wrapper classes can partially mitigate this, enabling model editing after loading would require NEURON itself to enhance its model serialization and deserialization mechanisms. Regarding the Zoom meeting invitation you previously mentioned — I was wondering if it's still valid? If you're available, I’d love to learn more about NEURON’s internal data structure design (such as My email is: 464270342@qq.com. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Overview of the feature
I'm trying to edit the coreneuron data exported using function
bbcorewrite, but I found that it's impossible to locate the mech var index.like I have 10 Iclamps, and I want to modify the 3rd Iclamp's amp value, but I can't just edit the 3rd var in the
xx_2.dat, because it's already sorted in some magical way.I tried using the
object_id(mech_obj,1)command, but it only return the order that I created the mech objects, it doesn't help.I tried setting
coreneuron.cell_permute = 0orh.cvode.cache_efficient(0), but the vars will be permuted anyway.Adding a custom range var (like
id) to mech will be a temporary solution, but if the model gets complicated, it's not an efficient way.How to get the var export order in NEURON? I tried looking for the code but didn't find where the order was changed.
And it doesn't seem like it have a API to export the info.
BTW: I found some macro defines in coreneuron's code
synapseIDandselected_for_report, it' seems like coreneuron don't know how to find the vars either, it also requires user toForeseeable Impact
Add a single API in Python, which can tell the user mech var export order.
Beta Was this translation helpful? Give feedback.
All reactions