""" A script for generating HTML docs from LEMS descriptions of the core NeuroML 2 Component Types """ import textwrap from decimal import Decimal from decimal import getcontext from lems.model.model import Model from lems.model.dynamics import OnStart from lems.model.dynamics import OnCondition from lems.model.dynamics import OnEvent from lems.model.dynamics import OnEntry from lems.model.dynamics import Transition from lems.model.dynamics import StateAssignment from lems.model.dynamics import EventOut import math # To display correct conversion values, we limit the precision context to 2 # places (required by Hz). Higher precisions, such as the default machine # precision include the usual issues with floating point arithmetic and do not # display exact conversions # # References: https://docs.python.org/3/tutorial/floatingpoint.html # https://docs.python.org/3/library/decimal.html#module-decimal getcontext().prec = 7 nml2_version = "2.2" nml2_branch = "master" col_width_left = "70" col_width_right = "100" spacer2 = " " spacer3 = " " spacer4 = " " spacer8 = spacer4 + spacer4 grey_style = " style=\"color:darkgrey\"" grey_small_style = " style=\"color:darkgrey;font-size:12px\"" grey_style_dark = " style=\"color:dimgrey\"" grey_style_dark_ital = " style=\"color:dimgrey;font-style:italic\"" grey_blue_style = " style=\"color:#85ACE1;font-style:italic\"" grey_small_style_dark = " style=\"color:dimgrey;font-size:12px\"" lems_xml_url = "https://github.com/NeuroML/NeuroML2/blob/%s/NeuroML2CoreTypes/" % nml2_branch #bioportal_url = "http://bioportal.bioontology.org/ontologies/46856/?p=terms&conceptid=cno:" bioportal_url = "https://bioportal.bioontology.org/ontologies/CNO/?p=classes&conceptid=" nml_src = "../NeuroML2CoreTypes" IF = "IF" THEN = "THEN" def category(name, rows=1, type="label-info"): return (textwrap.dedent( """
NOTE: the latest version of this documentation can be found on docs.neuroml.org!
%s |
%s |
Original LEMS ComponentType definitions: %s.xml " + \ " Schema against which NeuroML based on these should be valid: NeuroML_v%s.xsd |
Included file: %s
\n"%(inc.getFile().replace(".xml", ".html"),inc.getFile())''' if "Dimensions" in file: dimensions = model.dimensions dimensions = sorted(dimensions, key=lambda dim: dim.name) for dim in dimensions: contents += " \n" contents += "\n" contents += " " + dim.name + "\n" contents += " | \n" contents += "
\n"
contents2 = ""
format = "%s%i "
if dim.m is not None and dim.m != 0:
contents += format % ("M", dim.m)
if dim.l is not None and dim.l != 0:
contents += format % ("L", dim.l)
if dim.t is not None and dim.t != 0:
contents += format % ("T", dim.t)
if dim.i is not None and dim.i != 0:
contents += format % ("I", dim.i)
if dim.k is not None and dim.k != 0:
contents += format % ("K", dim.k)
if dim.n is not None and dim.n != 0:
contents += format % ("N", dim.n)
contents += " " for unit in units: if unit.dimension == dim.name: contents += " " + spacer4 + "Defined unit: %s" % (unit.symbol, unit.symbol) + "\n" contents += " | \n"
contents += "
\n" contents += " " + unit.symbol + "\n" contents += " | \n" contents += "
\n"
offset = ""
if unit.offset is not None and unit.offset != 0:
offset = " " + spacer4 + "Offset: " + str(unit.offset) scale = "" if unit.scale is not None and unit.scale != 1: scale = " " + spacer4 + "Scale: " + str(unit.scale) contents += spacer4 + "Dimension: " + dimension(unit.dimension, "", "") + " " + spacer4 + "Power of 10: " + str(unit.power) + offset + scale + " \n" for unit2 in model.units: if unit.symbol != unit2.symbol and unit.dimension == unit2.dimension: si_val = model.get_numeric_value("1%s" % unit.symbol, unit.dimension) unit_val = ((Decimal(si_val)/Decimal(math.pow(10,unit2.power))) / Decimal(unit2.scale))-Decimal(unit2.offset) scaled = float(unit_val) # to catch 60.0001 etc. if scaled>1 and int(scaled)!=scaled: if scaled-int(scaled)<0.001: scaled = int(scaled) if scaled>10000: scaled = '%.2e'%scaled else: scaled = '%s'%scaled if scaled.endswith('.0'): scaled = scaled[:-2] #contents += " " + spacer4 + "1 %s = %s %s 1: %s, 2: %s, si_val: %s, Decimal(unit2.scale): %s, unit_val: %s, Decimal(math.pow(10,unit2.power)): %s" % (unit.symbol, "%s" % scaled, unit2.symbol, unit2.symbol, factor1, factor2, si_val, Decimal(unit2.scale), unit_val, Decimal(math.pow(10,unit2.power))) contents += " " + spacer4 + "1 %s = %s %s" % (unit.symbol, "%s" % scaled, unit2.symbol, unit2.symbol) contents += " | \n"
contents += "
%sextends %s
" % (spacer4, comp_type_link(comp_type.extends)) # ext = "" if comp_type.extends is None else "%sextends %s"%(spacer4,comp_type.extends,comp_type.extends) contents += " \n" contents += "\n" classInfo = "" if comp_type.name.startswith("base"): contents += " " + comp_type.name + "\n" else: contents += " " + comp_type.name + "\n" contents += ext contents += " | \n" contents += "||
\n" contents += " " + desc + cnoLink contents += " | \n" contents += "||
" + param.name + "" + origin + " | \n" + dimension(param.dimension) + " | \n|
" + dp.name + " = " + dp.value + "" + origin + " | \n" + dimension(dp.dimension) + " | \n|
" + text.name + " | \n||
" + path.name + " | \n||
" + cr.name + " | \n" + comp_type_link(cr.type) + " | \n|
" + child_or_children.name + " | \n" + comp_type_link(child_or_children.type) + " | \n" + child_or_children.name + " | \n" + comp_type_link(child_or_children.type) + " | \n \n" if child_count > 0: contents += category("Child elements", child_count, type="label-success") contents += child_contents if children_count > 0: contents += category("Children elements", children_count, type="label-success") contents += children_contents if len(comp_type.constants) > 0: contents += "
" + const.name + " = " + const.value + format_description_small(const) + " | \n" + dimension(const.dimension) + " | \n|
" + exp.name + "" + origin + " | \n" + dimension(exp.dimension) + " | \n|
" + req.name + "" + origin + " | \n" + dimension(req.dimension) + " | \n|
" + ep.name + "" + origin + " | \nDirection: " + ep.direction + " | \n|
" + att.name + " | \n" + comp_type_link(att.type) + " | \n|
\n"
structure = None
if comp_type.structure is not None:
structure = comp_type.structure
if structure is not None and \
len(structure.withs) + len(structure.child_instances) + \
len(structure.multi_instantiates) + len(structure.event_connections) > 0:
contents += "Structure \n" for w in structure.withs: contents += spacer4 + "WITH " + w.instance + " AS " + w.as_ + " \n" for ci in structure.child_instances: contents += spacer4 + "CHILD INSTANCE: " + ci.component + " \n" for mi in structure.multi_instantiates: contents += spacer4 + "INSTANTIATE " + mi.number + " COMPONENTS OF TYPE " + mi.component + " \n" for ec in structure.event_connections: targetPort = "" if ec.target_port is None else ", TARGET PORT: " + ec.target_port + "" receiver = "" if ec.receiver is None else ", RECEIVER: " + ec.receiver + "" delay = "" if not hasattr(ec, 'delay') or ec.delay is None else ", DELAY: " + ec.delay + "" contents += spacer4 + "EVENT CONNECTION from " + ec.from_ + " TO " + ec.to + "" + receiver + targetPort + delay + " \n" if hasattr(ec, 'assign') and ec.assign is not None: contents += spacer4 + spacer4 + "ASSIGN " + ec.assign.property + " = " + ec.assign.value + " \n" contents += " \n" if len(dynamics.state_variables) > 0: contents += "State Variables \n" for sv in dynamics.state_variables: contents += spacer4 + "" + sv.name + "" + spacer4 + dimension(sv.dimension) + exposed_as(sv.exposure) + " \n" if len(dynamics.state_variables) > 0: contents += " \n" if dynamics.event_handlers is not None: os_content = "" oc_content = "" oe_content = "" for eh in dynamics.event_handlers: if isinstance(eh, OnStart): if len(os_content) == 0: os_content += "On Start \n" os = eh for ac in os.actions: if isinstance(ac, StateAssignment): os_content += spacer4 + "" + ac.variable + " = " + ac.value + " \n" os_content += " \n" if isinstance(eh, OnCondition): if len(oc_content) == 0: oc_content += "On Conditions \n" oc = eh test = format_expression(oc.test) oc_content += spacer4 + IF + " " + test + " " + THEN + " \n" for ac in oc.actions: if isinstance(ac, StateAssignment): oc_content += spacer4 + spacer4 + "" + ac.variable + " = " + ac.value + " \n" if isinstance(ac, EventOut): oc_content += spacer4 + spacer4 + "EVENT OUT on port " + ac.port + " \n" oc_content += " \n" if isinstance(eh, OnEvent): if len(oe_content) == 0: oe_content += "On Events \n" oe = eh oe_content += spacer4 + "EVENT IN on port: " + oe.port + " \n" for ac in oe.actions: if isinstance(ac, StateAssignment): oe_content += spacer4 + spacer4 + "" + ac.variable + " = " + ac.value + " \n" if isinstance(ac, EventOut): oe_content += spacer4 + spacer4 + "EVENT OUT on port " + ac.port + " \n" oe_content += " \n" contents += os_content contents += oc_content contents += oe_content if len(dynamics.derived_variables) > 0: contents += "Derived Variables \n" for dv in dynamics.derived_variables: res = dv.value if res is None: res = str.replace(dv.select, '/', '->') if dv.reduce: res = res + " (reduce method: " + dv.reduce + ")" contents += spacer4 + "" + dv.name + " = " + res + spacer4 + exposed_as(dv.exposure) + " \n" if len(dynamics.derived_variables) > 0: contents += " \n" if len(dynamics.conditional_derived_variables) > 0: contents += "Conditional Derived Variables \n" for cdv in dynamics.conditional_derived_variables: for case in cdv.cases: res = case.value cond = IF + " " + format_expression(case.condition) + " " + THEN + " " + spacer4 + spacer4 if case.condition else "OTHERWISE " + spacer4 + spacer4 contents += spacer4 + cond + "" + cdv.name + " = " + res + spacer4 + exposed_as(cdv.exposure) + " \n" contents += " \n" if len(dynamics.conditional_derived_variables) > 0: contents += " \n" if len(dynamics.time_derivatives) > 0: contents += "Time Derivatives \n" for td in dynamics.time_derivatives: contents += spacer4 + "d " + td.variable + " /dt = " + td.value + " \n" if len(dynamics.time_derivatives) > 0: contents += " \n" if len(dynamics.regimes) > 0: for rg in dynamics.regimes: initial = "" if rg.initial is None or rg.initial == "false" else " (initial)" contents += "Regime: " + rg.name + initial + " \n" oc_content = "" for eh in rg.event_handlers: if isinstance(eh, OnEntry): contents += spacer8 + "On Entry \n" oe = eh for ac in oe.actions: if isinstance(ac, StateAssignment): contents += spacer8 + spacer4 + "" + ac.variable + " = " + ac.value + " \n" contents += " \n" if isinstance(eh, OnCondition): if len(oc_content) == 0: oc_content += spacer8 + "On Conditions \n" oc = eh test = format_expression(oc.test) oc_content += spacer8 + spacer4 + IF + " " + test + " " + THEN + " \n" for ac in oc.actions: if isinstance(ac, StateAssignment): oc_content += spacer8 + spacer4 + spacer4 + "" + ac.variable + " = " + ac.value + " \n" if isinstance(ac, EventOut): oc_content += spacer8 + spacer4 + spacer4 + "EVENT OUT on port " + ac.port + " \n" if isinstance(ac, Transition): oc_content += spacer8 + spacer4 + spacer4 + "TRANSITION to REGIME " + ac.regime + " \n" oc_content += " \n" contents += oc_content if len(rg.time_derivatives) > 0: contents += spacer8 + "Time Derivatives \n" for td in rg.time_derivatives: contents += spacer8 + spacer4 + "d " + td.variable + " /dt = " + td.value + " \n" if len(rg.time_derivatives) > 0: contents += " \n" if len(dynamics.regimes) > 0: contents += " \n" contents += " | \n"
contents += "