def interpolation_demo(): interpol = moose.Interpol2D('/interpol2D') interpol.xmin = 0.0 interpol.xmax = 1.0 interpol.ymin = 0.0 interpol.ymax = 1.0 # Make a 50 element array with entries at equal distance from # [0,1) and reshape it into a 10x5 matrix and assign to table. matrix = np.linspace(0, 1.0, 50).reshape(10, 5) print('Setting table to') print(matrix) interpol.tableVector2D = matrix # interpolating beyond top left corner. # value should be pos = (0.8, 0.3) print(('Interpolated value at', pos)) print((interpol.z[pos[0], pos[1]])) print(('Point going out of bound on both x and y', interpol.z[1.1, 1.1])) print(('Point going out of bound on both x and y', interpol.z[0.5, 1.1]))
def readChannelML(self, channelElement, params={}, units="SI units"): """Loads a single channel """ # I first calculate all functions assuming a consistent system of units. # While filling in the A and B tables, I just convert to SI. Also # convert gmax and Erev. if 'Physiological Units' in units: # see pg 219 (sec 13.2) of Book of Genesis Vfactor = 1e-3 # V from mV Tfactor = 1e-3 # s from ms Gfactor = 1e1 # S/m^2 from mS/cm^2 concfactor = 1e6 # Mol = mol/m^-3 from mol/cm^-3 elif 'SI Units' in units: Vfactor = 1.0 Tfactor = 1.0 Gfactor = 1.0 concfactor = 1.0 else: debug.printDebug("ERR", "wrong units %s. Existing... " % units, frame=inspect.currentframe()) raise UserWarning, "Unknown units" # creates /library in MOOSE tree; elif present, wraps channel_name = channelElement.attrib['name'] if utils.neuroml_debug: msg = "Loading channel {} into {} ".format(channel_name, self.libraryPath) debug.printDebug("INFO", msg) IVrelation = channelElement.find('./{' + self.cml + '}current_voltage_relation') concdep = IVrelation.find('./{' + self.cml + '}conc_dependence') cPath = os.path.join(self.libraryPath, channel_name) if concdep is None: channel = moose.HHChannel(cPath) else: channel = moose.HHChannel2D(cPath) if IVrelation.attrib['cond_law'] == "ohmic": channel.Gbar = float(IVrelation.attrib['default_gmax']) * Gfactor channel.Ek = float(IVrelation.attrib['default_erev']) * Vfactor channelIon = moose.Mstring(channel.path + '/ion') channelIon.value = IVrelation.attrib['ion'] if concdep is not None: channelIonDependency = moose.Mstring(channel.path + '/ionDependency') channelIonDependency.value = concdep.attrib['ion'] nernstnote = IVrelation.find('./{' + utils.meta_ns + '}notes') if nernstnote is not None: # the text in nernstnote is "Nernst,Cout=<float>,z=<int>" nernst_params = string.split(nernstnote.text, ',') if nernst_params[0] == 'Nernst': nernstMstring = moose.Mstring(channel.path + '/nernst_str') nernstMstring.value = str( float(string.split(nernst_params[1], '=')[1]) * concfactor) + ',' + str( int(string.split(nernst_params[2], '=')[1])) gates = IVrelation.findall('./{' + self.cml + '}gate') if len(gates) > 3: msg = "Sorry! Maximum x, y, and z (three) gates are possible in\ MOOSE/Genesis" debug.printDebug("ERR", msg, frame=inspect.currentframe()) raise UserWarning, "Bad value or parameter" # These are the names that MOOSE uses to create gates. gate_full_name = ['gateX', 'gateY', 'gateZ'] # if impl_prefs tag is present change VMIN, VMAX and NDIVS impl_prefs = channelElement.find('./{' + self.cml + '}impl_prefs') if impl_prefs is not None: table_settings = impl_prefs.find('./{' + self.cml + '}table_settings') # some problem here... disable VMIN_here = float(table_settings.attrib['min_v']) VMAX_here = float(table_settings.attrib['max_v']) NDIVS_here = int(table_settings.attrib['table_divisions']) dv_here = (VMAX_here - VMIN_here) / NDIVS_here else: # default VMIN, VMAX and dv are in SI convert them to current # calculation units used by channel definition while loading into # tables, convert them back to SI VMIN_here = utils.VMIN / Vfactor VMAX_here = utils.VMAX / Vfactor NDIVS_here = utils.NDIVS dv_here = utils.dv / Vfactor offset = IVrelation.find('./{' + self.cml + '}offset') if offset is None: vNegOffset = 0.0 else: vNegOffset = float(offset.attrib['value']) self.parameters = [] for parameter in channelElement.findall('.//{' + self.cml + '}parameter'): self.parameters.append( (parameter.attrib['name'], float(parameter.attrib['value']))) for num, gate in enumerate(gates): # if no q10settings tag, the q10factor remains 1.0 if present but no # gate attribute, then set q10factor if there is a gate attribute, # then set it only if gate attrib matches gate name self.q10factor = 1.0 self.gate_name = gate.attrib['name'] q10sets = IVrelation.findall('./{' + self.cml + '}q10_settings') for q10settings in q10sets: # self.temperature from neuro.utils if 'gate' in list(q10settings.attrib.keys()): if q10settings.attrib['gate'] == self.gate_name: self.setQ10(q10settings) break else: self.setQ10(q10settings) # HHChannel2D crashing on setting Xpower! temperamental! If you # print something before, it gives cannot creategate from copied # channel, else crashes Setting power first. This is necessary # because it also initializes the gate's internal data structures as # a side effect. Alternatively, gates can be initialized explicitly # by calling HHChannel.createGate(). gate_power = float(gate.get('instances')) if num == 0: channel.Xpower = gate_power if concdep is not None: channel.Xindex = "VOLT_C1_INDEX" elif num == 1: channel.Ypower = gate_power if concdep is not None: channel.Yindex = "VOLT_C1_INDEX" elif num == 2: channel.Zpower = gate_power if concdep is not None: channel.Zindex = "VOLT_C1_INDEX" ## Getting handle to gate using the gate's path. gate_path = os.path.join(channel.path, gate_full_name[num]) if concdep is None: moosegate = moose.HHGate(gate_path) # set SI values inside MOOSE moosegate.min = VMIN_here * Vfactor moosegate.max = VMAX_here * Vfactor moosegate.divs = NDIVS_here ## V.IMP to get smooth curves, else even with 3000 divisions ## there are sudden transitions. moosegate.useInterpolation = True else: moosegate = moose.HHGate2D(gate_path) # If alpha and beta functions exist, make them here for transition in gate.findall('./{' + self.cml + '}transition'): # make python functions with names of transitions... fn_name = transition.attrib['name'] # I assume that transitions if present are called alpha and beta # for forwand backward transitions... if fn_name in ['alpha', 'beta']: self.make_cml_function(transition, fn_name, concdep) else: debug.printDebug( "ERROR", "Unsupported transition {0}".format(fn_name)) sys.exit() time_course = gate.find('./{' + self.cml + '}time_course') # tau is divided by self.q10factor in make_function() thus, it gets # divided irrespective of <time_course> tag present or not. if time_course is not None: self.make_cml_function(time_course, 'tau', concdep) steady_state = gate.find('./{' + self.cml + '}steady_state') if steady_state is not None: self.make_cml_function(steady_state, 'inf', concdep) if concdep is None: ca_name = '' # no Ca dependence else: # Ca dependence ca_name = ',' + concdep.attrib['variable_name'] # Create tau() and inf() if not present, from alpha() and beta() for fn_element, fn_name, fn_expr in [ (time_course, 'tau', "1/(alpha+beta)"), (steady_state, 'inf', "alpha/(alpha+beta)") ]: # put in args for alpha and beta, could be v and Ca dep. expr_string = self.replace(fn_expr, 'alpha', 'self.alpha(v' + ca_name + ')') expr_string = self.replace(expr_string, 'beta', 'self.beta(v' + ca_name + ')') # if time_course/steady_state are not present, then alpha annd # beta transition elements should be present, and fns created. if fn_element is None: self.make_function(fn_name, 'generic', expr_string=expr_string, concdep=concdep) # non Ca dependent channel if concdep is None: # while calculating, use the units used in xml defn, while # filling in table, I convert to SI units. v0 = VMIN_here - vNegOffset n_entries = NDIVS_here + 1 tableA = [0.0] * n_entries tableB = [0.0] * n_entries for i in range(n_entries): v = v0 + (i * dv_here) inf = self.inf(v) tau = self.tau(v) # convert to SI before writing to table # qfactor is already in inf and tau tableA[i] = (inf / tau) / Tfactor tableB[i] = (1.0 / tau) / Tfactor moosegate.tableA = tableA moosegate.tableB = tableB ## Ca dependent channel else: # UNITS: while calculating, use the units used in xml defn, # while filling in table, I convert to SI units. Note here Ca # units do not enter, but units of CaMIN, CaMAX and ca_conc in # fn expr should match. v = VMIN_here - vNegOffset CaMIN = float(concdep.attrib['min_conc']) CaMAX = float(concdep.attrib['max_conc']) CaNDIVS = 100 dCa = (CaMAX - CaMIN) / CaNDIVS # CAREFUL!: tableA = [[0.0]*(CaNDIVS+1)]*(NDIVS_here+1) will not # work! * does a shallow copy, same list will get repeated 200 # times! Thus setting tableA[35][1] = 5.0 will set all rows, # 1st col to 5.0!!!! tableA = [[0.0] * (CaNDIVS + 1) for i in range(NDIVS_here + 1)] tableB = [[0.0] * (CaNDIVS + 1) for i in range(NDIVS_here + 1)] for i in range(NDIVS_here + 1): Ca = CaMIN for j in range(CaNDIVS + 1): inf = self.inf(v, Ca) tau = self.tau(v, Ca) # convert to SI (Tfactor) before writing to table # qfactor is already in inf and tau tableA[i][j] = (inf / tau) / Tfactor tableB[i][j] = (1.0 / tau) / Tfactor Ca += dCa v += dv_here # Presently HHGate2D doesn't allow the setting of tables as 2D # vectors directly #moosegate.tableA = tableA #moosegate.tableB = tableB # Instead, I wrap the interpol2D objects inside HHGate2D and set # the tables moosegate_tableA = moose.Interpol2D(moosegate.path + '/tableA') # set SI values inside MOOSE moosegate_tableA.xmin = VMIN_here * Vfactor moosegate_tableA.xmax = VMAX_here * Vfactor moosegate_tableA.xdivs = NDIVS_here #moosegate_tableA.dx = dv_here*Vfactor moosegate_tableA.ymin = CaMIN * concfactor moosegate_tableA.ymax = CaMAX * concfactor moosegate_tableA.ydivs = CaNDIVS #moosegate_tableA.dy = dCa*concfactor moosegate_tableA.tableVector2D = tableA moosegate_tableB = moose.Interpol2D(moosegate.path + '/tableB') ## set SI values inside MOOSE moosegate_tableB.xmin = VMIN_here * Vfactor moosegate_tableB.xmax = VMAX_here * Vfactor moosegate_tableB.xdivs = NDIVS_here #moosegate_tableB.dx = dv_here*Vfactor moosegate_tableB.ymin = CaMIN * concfactor moosegate_tableB.ymax = CaMAX * concfactor moosegate_tableB.ydivs = CaNDIVS #moosegate_tableB.dy = dCa*concfactor moosegate_tableB.tableVector2D = tableB