diff --git a/brian2tools/mdexport/expander.py b/brian2tools/mdexport/expander.py index 0cba6473..374cc620 100644 --- a/brian2tools/mdexport/expander.py +++ b/brian2tools/mdexport/expander.py @@ -9,13 +9,16 @@ from sympy.abc import * from markdown_strings import * from jinja2 import Template -from .template import templates import numpy as np import re import inspect import datetime import brian2 +from jinja2 import Environment, PackageLoader, ChoiceLoader, FileSystemLoader, select_autoescape, TemplateNotFound + + + # define variables for often used delimiters endll = '\n\n' endl = '\n' @@ -104,6 +107,12 @@ def __init__(self, brian_verbose=False, include_monitors=False, self.add_meta = add_meta self.github_md = github_md + def set_template_dir(self, template_dir): + self.env = Environment( + loader=ChoiceLoader([FileSystemLoader(template_dir), PackageLoader("brian2tools")]), + autoescape=select_autoescape() + ) + def check_plural(self, iterable, singular_word=None, allow_constants=True, is_int=False): """ @@ -291,6 +300,7 @@ def create_md_string(self, net_dict, template_name): Create markdown text by checking the standard dictionary and call required expand functions and arrange the descriptions """ + template_name = template_name # expand network header overall_string = self.expand_network_header(net_dict) @@ -305,40 +315,49 @@ def create_md_string(self, net_dict, template_name): # map expand functions for particular components # h: "general user" naming / 'hb': "Brian" user naming - func_map = {'neurongroup': {'f': self.expand_NeuronGroup, - 'hb': 'NeuronGroup', - 'h': 'Neuron population', 'order': 1}, - 'poissongroup': {'f': self.expand_PoissonGroup, - 'hb': 'PoissonGroup', - 'h': 'Poisson spike source', - 'order': 2}, - 'spikegeneratorgroup': - {'f': self.expand_SpikeGeneratorGroup, - 'hb': 'SpikeGeneratorGroup', - 'h': 'Spike generating source', - 'order': 2}, - 'statemonitor': {'f': self.expand_StateMonitor, - 'hb': 'StateMonitor', - 'h': 'Activity recorder', 'order': 4}, - 'spikemonitor': {'f': self.expand_SpikeMonitor, - 'hb': 'SpikeMonitor', - 'h': 'Spiking activity recorder', - 'order': 4}, - 'eventmonitor': {'f': self.expand_EventMonitor, - 'hb': 'EventMonitor', - 'h': 'Event activity recorder', - 'order': 4}, - 'populationratemonitor': - {'f': self.expand_PopulationRateMonitor, - 'hb': 'PopulationRateMonitor', - 'h': 'Population rate recorder', - 'order': 4}, - 'synapses': {'f': self.expand_Synapses, - 'hb': 'Synapses', - 'h': 'Synapse', 'order': 3}, - 'poissoninput': {'f': self.expand_PoissonInput, - 'hb': 'PoissonInput', - 'h': 'Poisson input', 'order': 0}} + func_map = { + "neurongroup": { + "hb": "NeuronGroup", + "h": "Neuron population", + "order": 1, + }, + "poissongroup": { + "hb": "PoissonGroup", + "h": "Poisson spike source", + "order": 2, + }, + "spikegeneratorgroup": { + "hb": "SpikeGeneratorGroup", + "h": "Spike generating source", + "order": 2, + }, + "statemonitor": { + "hb": "StateMonitor", + "h": "Activity recorder", + "order": 4, + }, + "spikemonitor": { + "hb": "SpikeMonitor", + "h": "Spiking activity recorder", + "order": 4, + }, + "eventmonitor": { + "hb": "EventMonitor", + "h": "Event activity recorder", + "order": 4, + }, + "populationratemonitor": { + "hb": "PopulationRateMonitor", + "h": "Population rate recorder", + "order": 4, + }, + "synapses": {"hb": "Synapses", "h": "Synapse", "order": 3}, + "poissoninput": { + "hb": "PoissonInput", + "h": "Poisson input", + "order": 0, + }, + } # loop over each order and expand the item # (same complexity as sorting the dict) order_list = [0, 1, 2, 3, 4] @@ -375,10 +394,8 @@ def create_md_string(self, net_dict, template_name): for connector in initializers_connectors if connector['type'] == 'connect' and connector['synapses'] == obj_mem['name']] - if obj_key == 'neurongroup' and current_order == 1: - obj_mem['template_name'] = template_name run_string += ('- ' + - func_map[obj_key]['f'](obj_mem)) + self.expand_group(obj_mem, f"{func_map[obj_key]['hb']}-{template_name}.md")) if self.keep_initializer_order: # differentiate connectors and initializers @@ -471,59 +488,29 @@ def expand_run_header(self, run_dict, run_indx, single_run=False): md_str += endl return md_str - - def expand_NeuronGroup(self, neurongrp): + def expand_group(self, group, template_name): """ - Expand NeuronGroup from standard dictionary + Expand group() header Parameters ---------- - neurongrp : dict - Standard dictionary of NeuronGroup + group : groupname + ex : - neurongrp,poisongrp .... + + template_name : string + full template name along with the group and template_type """ - template_name = neurongrp['template_name'] - # start expanding - md_str = '' - # name and size - md_str += ('Group ' + bold(neurongrp['name']) + ', consisting of ' + - bold(neurongrp['N']) + ' neurons.' + endll) - # expand model equations - md_str += tab + bold('Model dynamics:') + endll - md_str += self.expand_equations(neurongrp['equations']) - if neurongrp['user_method']: - md_str += (tab + 'The equations are integrated with the \'' + - neurongrp['user_method'] + '\' method.' + endll) - # expand associated events - if 'events' in neurongrp: - md_str += tab + bold('Events:') + endll - md_str += self.expand_events(neurongrp['events']) - # expand identifiers associated - if 'identifiers' in neurongrp: - md_str += tab + bold('Constants:') + ' ' - md_str += self.expand_identifiers(neurongrp['identifiers']) + endll - if not self.keep_initializer_order and 'initializer' in neurongrp and len(neurongrp['initializer']): - md_str += tab + bold('Initial values:') + '\n' - for initializer in neurongrp['initializer']: - md_str += tab + '* ' + self.expand_initializer(initializer) + '\n' - md_str += '\n' - # expand run_regularly() - if 'run_regularly' in neurongrp: - md_str += (tab + bold('Run regularly') + - self.check_plural(neurongrp['run_regularly']) + ': ' + endll) - for run_reg in neurongrp['run_regularly']: - md_str += self.expand_runregularly(run_reg) + try: + print (template_name) + template = self.env.get_template(template_name) + md_str = template.render(group=group, expander=self) + print (md_str) + return md_str + except TemplateNotFound as e: + raise ValueError(f"Template '{template_name}' not found.") - # Create Jinja2 Template object - if template_name not in templates : - print(md_str) - return md_str - # Create Jinja2 Template object - template = Template(templates[template_name]) - # # Render the template with the provided NeuronGroup dictionary - md_str = template.render(neurongrp=neurongrp) - print (md_str) - return md_str + def expand_SpikeSource(self, source): @@ -797,151 +784,10 @@ def expand_connector(self, connector): self.expand_identifiers(connector['identifiers'])) return con_str + '.' + endll - def expand_PoissonGroup(self, poisngrp): - """ - Expand PoissonGroup from standard dictionary - - Parameters - ---------- - - poisngrp : dict - Standard dictionary of PoissonGroup - """ - - md_str = '' - md_str += (tab + 'Name ' + bold(poisngrp['name']) + ', with \ - population size ' + bold(poisngrp['N']) + - ' and rate as ' + self.render_expression(poisngrp['rates']) + - '.' + endll) - if 'identifiers' in poisngrp: - md_str += tab + bold('Constants:') + endll - md_str += self.expand_identifiers(poisngrp['identifiers']) - if 'run_regularly' in poisngrp: - md_str += tab + bold('Run regularly: ') + endll - for run_reg in poisngrp['run_regularly']: - md_str += self.expand_runregularly(run_reg) - - return md_str - - def expand_SpikeGeneratorGroup(self, spkgen): - """ - Expand SpikeGeneratorGroup from standard dictionary - - Parameters - ---------- - - spkgen : dict - Standard dictionary of SpikeGeneratorGroup - """ - md_str = '' - md_str += (tab + 'Name ' + bold(spkgen['name']) + - ', with population size ' + bold(spkgen['N']) + - ', has neuron' + self.check_plural(spkgen['indices']) + ': ' + - self.prepare_array(spkgen['indices']) + - ' that spike at times ' + - self.prepare_array(spkgen['times']) + - ', with period ' + str(spkgen['period']) + - '.' + endll) - if 'run_regularly' in spkgen: - md_str += tab + bold('Run regularly: ') + endll - for run_reg in spkgen['run_regularly']: - md_str += self.expand_runregularly(run_reg) - - return md_str - - def expand_StateMonitor(self, statemon): - """ - Expand StateMonitor from standard dictionary - - Parameters - ---------- - - statemon : dict - Standard dictionary of StateMonitor - """ - md_str = '' - md_str += (tab + 'Monitors variable' + - self.check_plural(statemon['variables']) + ': ' + - ','.join( - [self.render_expression(var) for var in statemon['variables']] - ) + - ' of ' + self.expand_SpikeSource(statemon['source'])) - if isinstance(statemon['record'], bool): - if statemon['record']: - md_str += ' for all members' - else: - # another bad hack (before with initializers) - if not statemon['record'].size: - md_str += ' for no member' - else: - md_str += (', for member' + - self.check_plural(statemon['record']) + - ': ' + - - ','.join([str(ind) for ind in statemon['record']])) - return md_str + endll - - def expand_SpikeMonitor(self, spikemon): - """ - Expand SpikeMonitor from standard representation - - Parameters - ---------- - - spikemon : dict - Standard dictionary of SpikeMonitor - """ - return self.expand_EventMonitor(spikemon) - - def expand_EventMonitor(self, eventmon): - """ - Expand EventMonitor from standard representation - - Parameters - ---------- - - eventmon : dict - Standard dictionary of EventMonitor - """ - md_str = '' - md_str += (tab + 'Monitors variable' + - self.check_plural(eventmon['variables']) + ': ' + - ','.join( - [self.render_expression(var) for var in eventmon['variables']] - ) + - ' of ' + self.expand_SpikeSource(eventmon['source'])) - if isinstance(eventmon['record'], bool): - if eventmon['record']: - md_str += ' for all members' - else: - if not eventmon['record'].size: - md_str += ' for no member' - else: - md_str += ( - ', for member' + self.check_plural(eventmon['record']) + - ': ' + - ','.join([str(ind) for ind in eventmon['record']])) - md_str += (' when event ' + bold(eventmon['event']) + - ' is triggered') - - return md_str + endll - - def expand_PopulationRateMonitor(self, popratemon): - """ - Expand PopulationRateMonitor - - Parameters - ---------- - - popratemon : dict - PopulationRateMonitor's baseexport dictionary - """ - md_str = '' - md_str += (tab + 'Monitors the population of ' + - self.expand_SpikeSource(popratemon['source']) + - '.' + endll) - return md_str + + + def expand_pathway(self, pathway): """ Expand `SynapticPathway` @@ -1006,79 +852,7 @@ def expand_summed_variables(self, sum_variables): sum_var_str += self.expand_summed_variable(sum_var) return sum_var_str - def expand_Synapses(self, synapse): - """ - Expand `Synapses` details from Baseexporter dictionary - - Parameters - ---------- - - synapse : dict - Dictionary representation of `Synapses` object - """ - md_str = '' - md_str += (tab + 'Connections ' + bold(synapse['name']) + ', connecting ' + - self.expand_SpikeSource(synapse['source']) + - ' to ' + self.expand_SpikeSource(synapse['target']) - ) - # expand connectors - if not self.keep_initializer_order and 'connectors' in synapse: - if len(synapse['connectors']) > 1: - raise NotImplementedError('Only a single connect statement per Synapses object supported.') - if len(synapse['connectors']): - md_str += tab + self.expand_connector(synapse['connectors'][0]) - else: - md_str += '.' + endll - # expand model equations - if 'equations' in synapse: - md_str += tab + bold('Model dynamics:') + endll - md_str += self.expand_equations(synapse['equations']) - if 'user_method' in synapse: - md_str += (tab + 'The equations are integrated with the \'' + - synapse['user_method'] + '\' method.' + endll) - # expand pathways using `expand_pathways` - if 'pathways' in synapse: - md_str += self.expand_pathways(synapse['pathways']) - if 'equations' not in synapse and 'identifiers' in synapse: - # Put the external constants right here - md_str += tab + ', where ' + self.expand_identifiers(synapse['identifiers']) + '.' - md_str += endll - # expand summed_variables using `expand_summed_variables` - if 'summed_variables' in synapse: - md_str += tab + bold('Summed variables:') + endll - md_str += self.expand_summed_variables(synapse['summed_variables']) - # expand identifiers if defined - if 'identifiers' in synapse and 'equations' in synapse: - md_str += tab + bold('Constants:') + ' ' - md_str += self.expand_identifiers(synapse['identifiers']) + endll - if not self.keep_initializer_order and 'initializer' in synapse and len(synapse['initializer']): - md_str += tab + bold('Initial values:') + '\n' - for initializer in synapse['initializer']: - md_str += tab + '* ' + self.expand_initializer(initializer) + '\n' - md_str += '\n' - return md_str - - def expand_PoissonInput(self, poinp): - """ - Expand PoissonInput - - Parameters - ---------- - - poinp : dict - Standard dictionary representation for PoissonInput - """ - md_str = '' - md_str += (tab + 'PoissonInput with size ' + bold(poinp['N']) + - ' gives input to variable ' + - self.render_expression(poinp['target_var']) + - ' with rate ' + self.render_expression(poinp['rate']) + - ' and weight of ' + self.render_expression(poinp['weight']) + - endll) - if 'identifiers' in poinp: - md_str += tab + bold('Constants:') + endll - md_str += self.expand_identifiers(poinp['identifiers']) - return md_str + def expand_runregularly(self, run_reg): """ diff --git a/brian2tools/mdexport/mdexporter.py b/brian2tools/mdexport/mdexporter.py index 89a756dc..abe4f296 100644 --- a/brian2tools/mdexport/mdexporter.py +++ b/brian2tools/mdexport/mdexporter.py @@ -14,7 +14,7 @@ class MdExporter(BaseExporter): """ def build(self, direct_call=True, debug=False, expander=None, - filename=None, additional_formats=None, template_type=None): + filename=None, additional_formats=None, template_name='default', template_dir=None): """ Build the exporter @@ -41,7 +41,7 @@ def build(self, direct_call=True, debug=False, expander=None, can specify them under this variable and the options are pdf, latex, html and all. - template_type : str + template_name : str Based on your selected template, it will rendered otherwise a default template will be used for rendering """ @@ -79,8 +79,12 @@ def build(self, direct_call=True, debug=False, expander=None, # default standard md expander self.expander = MdExpander() + if template_dir is not None: + self.expander.set_temp_dir_path(template_dir) + + # start creating markdown descriptions using expander - self.md_text = self.expander.create_md_string(self.runs, template_type) + self.md_text = self.expander.create_md_string(self.runs, template_name) # check output filename if filename: diff --git a/brian2tools/mdexport/template.py b/brian2tools/mdexport/template.py deleted file mode 100644 index c9445716..00000000 --- a/brian2tools/mdexport/template.py +++ /dev/null @@ -1,54 +0,0 @@ -# Define the Jinja2 template string -templates = { - 'template_str' : """ - ## Network details - - **Neuron population:** - - Group {{ neurongrp.name }}, consisting of {{ neurongrp.N }} neurons. - - # Model dynamics - {% for key, eqn in neurongrp.equations.items() %} - - $\frac{d}{d t} {{ key }}$ = {{ eqn.expr }}{% if eqn.unit %} [{{ eqn.unit }}]{% endif %} - {% endfor %} - - {% if neurongrp.user_method %} - The equations are integrated with the '{{ neurongrp.user_method }}' method. - {% endif %} - - # Events (if present) - {% if 'events' in neurongrp %} - **Events:** - - {% for event, details in neurongrp.events.items() %} - - If {{ details.threshold.code }}, a {{ event }} event is triggered and {{ details.reset.code }}. - {% endfor %} - {% endif %} - - # Constants (if present) - {% if 'identifiers' in neurongrp %} - **Constants:** - - {% for identifier, value in neurongrp.identifiers.items() %} - - {{ identifier }}: {{ value }} - {% endfor %} - {% endif %} - - # Initial values (if present) - {% if 'initializer' in neurongrp and neurongrp['initializer'] %} - **Initial values:** - - {% for initializer in neurongrp['initializer'] %} - - {{ initializer.variable }}: {{ initializer.value }}{% if initializer.unit %} [{{ initializer.unit }}]{% endif %} - {% endfor %} - {% endif %} - - # Run regularly (if present) - {% if 'run_regularly' in neurongrp %} - **Run regularly:** - - {% for run_reg in neurongrp['run_regularly'] %} - - {{ run_reg }} - {% endfor %} - {% endif %} -""" -} diff --git a/brian2tools/templates/EventMonitor-default.md b/brian2tools/templates/EventMonitor-default.md new file mode 100644 index 00000000..13128757 --- /dev/null +++ b/brian2tools/templates/EventMonitor-default.md @@ -0,0 +1,7 @@ +Monitors variable{{ expander.check_plural(group['variables']) }}: {%- for var in group['variables'] -%} + {{ expander.render_expression(var) }}{%- if not loop.last -%}, {%- endif -%} +{%- endfor %} of {{ expander.expand_SpikeSource(group['source']) }} {%- if group['record'] is boolean -%} + {%- if group['record'] -%} for all members {%- else -%} for no member {%- endif -%} +{%- else -%} + {%- if group['record']|length == 0 -%} for no member {%- else -%} for member{{ expander.check_plural(group['record']) }}: {{ group['record'] | join(', ') }} {%- endif -%} +{%- endif -%} when event **{{ group['event'] }}** is triggered diff --git a/brian2tools/templates/EventMonitor-table.md b/brian2tools/templates/EventMonitor-table.md new file mode 100644 index 00000000..e6d1ea1c --- /dev/null +++ b/brian2tools/templates/EventMonitor-table.md @@ -0,0 +1,10 @@ +| **Monitors** | **Variables** | **Source** | **Record** | **Event** | +|-----------------|------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|------------------------------------------------------------------------------------------------------------|-------------------------------------| +| Monitors variable{{ expander.check_plural(group['variables']) }}: {%- for var in group['variables'] -%} + {{ expander.render_expression(var) }}{%- if not loop.last -%}, {%- endif -%} +{%- endfor %} | of {{ expander.expand_SpikeSource(group['source']) }} | + {%- if group['record'] is boolean -%} + {%- if group['record'] -%} for all members {%- else -%} for no member {%- endif -%} + {%- else -%} + {%- if group['record']|length == 0 -%} for no member {%- else -%} for member{{ expander.check_plural(group['record']) }}: {{ group['record'] | join(', ') }} {%- endif -%} + {%- endif -%} | when event **{{ group['event'] }}** is triggered | diff --git a/brian2tools/templates/NeuronGroup-default.md b/brian2tools/templates/NeuronGroup-default.md new file mode 100644 index 00000000..70a55e49 --- /dev/null +++ b/brian2tools/templates/NeuronGroup-default.md @@ -0,0 +1,30 @@ +## Network details + **Neuron population:** +Group {{ (group['name']) }}, consisting of {{ (group['N']) }} neurons. +{{ tab }}{{ ('Model dynamics:') }} +{{ expander.expand_equations(group['equations']) }} +{% if group['user_method'] %} + {{ tab }}The equations are integrated with the '{{ group['user_method'] }}' method. +{% endif %} +{% if 'events' in group %} + {{ tab }}{{ ('Events:') }} + {{ expander.expand_events(group['events']) }} +{% endif %} +{% if 'identifiers' in group %} + {{ tab }}{{ ('Constants:') }} {{ expander.expand_identifiers(group['identifiers']) }} +{% endif %} +{% if not expander.keep_initializer_order and 'initializer' in group and group['initializer']|length %} + {{ tab }}{{ ('Initial values:') }} + {% for initializer in group['initializer'] %} + {{ tab }}* {{ expander.expand_initializer(initializer) }} + {% endfor %} +{% endif %} +{% if 'run_regularly' in group %} + {{ tab }}{{ ('Run regularly') }}{{ expander.check_plural(group['run_regularly']) }}: + {% for run_reg in group['run_regularly'] %} + {{ expander.expand_runregularly(run_reg) }} + {% endfor %} +{% endif %} + + + diff --git a/brian2tools/templates/NeuronGroup-table.md b/brian2tools/templates/NeuronGroup-table.md new file mode 100644 index 00000000..80f66c87 --- /dev/null +++ b/brian2tools/templates/NeuronGroup-table.md @@ -0,0 +1,8 @@ +|-------------------------------|------------------------------------------------| +| **Neuron population** | Group {{ (group['name']) }}, consisting of {{ (group['N']) }} neurons. | +| **Model dynamics** | {{ expander.expand_equations(group['equations']) }} | +| **Integration method** | {% if group['user_method'] %} The equations are integrated with the '{{ group['user_method'] }}' method. {% endif %} | +| **Events** (if present) | {% if 'events' in group %} {{ expander.expand_events(group['events']) }} {% endif %} | +| **Constants** (if present) | {% if 'identifiers' in group %} {{ expander.expand_identifiers(group['identifiers']) }} {% endif %} | +| **Initial values** (if present)| {% if not expander.keep_initializer_order and 'initializer' in group and group['initializer']|length %} {% for initializer in group['initializer'] %} {{ initializer.variable }}: {{ initializer.value }}{% if initializer.unit %} [{{ initializer.unit }}]{% endif %} {% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} | +| **Run regularly** (if present)| {% if 'run_regularly' in group %} {% for run_reg in group['run_regularly'] %} {{ expander.expand_runregularly(run_reg) }} {% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} | diff --git a/brian2tools/templates/PoissonGroup-default.md b/brian2tools/templates/PoissonGroup-default.md new file mode 100644 index 00000000..d79ff7ba --- /dev/null +++ b/brian2tools/templates/PoissonGroup-default.md @@ -0,0 +1,17 @@ +Name {{ group['name'] }} of population size {{ group['N'] }} and rate as {{ expander.render_expression(group['rates']) }}. + + {% if group.get('identifiers', None) %} + Constants: + {{ expander.expand_identifiers(group['identifiers']) }} + {% endif %} + + {% if group.get('run_regularly', None) %} + + Run regularly: + {% for run_reg in group['run_regularly'] %} + {{ expander.expand_runregularly(run_reg) }} + {% endfor %} + {% endif %} + + + diff --git a/brian2tools/templates/PoissonGroup-table.md b/brian2tools/templates/PoissonGroup-table.md new file mode 100644 index 00000000..7c4f2289 --- /dev/null +++ b/brian2tools/templates/PoissonGroup-table.md @@ -0,0 +1,7 @@ + | **Variable** | **Value** | +|---------------------------------|------------------------------------------------| +| **Name** | {{ group['name'] }} | +| **Population size** | {{ group['N'] }} | +| **Rate** | {{ expander.render_expression(group['rates']) }} | +| **Constants** (if present) | {% if group.get('identifiers', None) %} {{ expander.expand_identifiers(group['identifiers']) }} {% endif %} | +| **Run regularly** (if present) | {% if group.get('run_regularly', None) %} {% for run_reg in group['run_regularly'] %} {{ expander.expand_runregularly(run_reg) }} {% endfor %} {% endif %} | \ No newline at end of file diff --git a/brian2tools/templates/PoissonInput-default.md b/brian2tools/templates/PoissonInput-default.md new file mode 100644 index 00000000..c9a599d7 --- /dev/null +++ b/brian2tools/templates/PoissonInput-default.md @@ -0,0 +1,10 @@ +{# Jinja2 template for PoissonInput in a simple text format #} + +PoissonInput with size {{ group['N'] }} gives input to variable {{ expander.render_expression(group['target_var']) }} with rate {{ expander.render_expression(group['rate']) }} and weight of {{ expander.render_expression(group['weight']) }}. + +{% if 'identifiers' in group %} +**Constants:** +{% for identifier, value in group['identifiers'].items() %} +- {{ identifier }}: {{ value }} +{% endfor %} +{% endif %} diff --git a/brian2tools/templates/PoissonInput-table.md b/brian2tools/templates/PoissonInput-table.md new file mode 100644 index 00000000..543c4d38 --- /dev/null +++ b/brian2tools/templates/PoissonInput-table.md @@ -0,0 +1,8 @@ +{# Jinja2 template for PoissonInput in table format #} + +|-------------------------------|------------------------------------------------| +| **PoissonInput Size** | {{ group['N'] }} | +| **Target Variable** | {{ expander.render_expression(group['target_var']) }} | +| **Rate** | {{ expander.render_expression(group['rate']) }} | +| **Weight** | {{ expander.render_expression(group['weight']) }} | +| **Constants** (if present) | {% if 'identifiers' in group %} {% for identifier, value in group['identifiers'].items() %} {{ identifier }}: {{ value }} {% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} | diff --git a/brian2tools/templates/PopulationRateMonitor-default.md b/brian2tools/templates/PopulationRateMonitor-default.md new file mode 100644 index 00000000..5c373366 --- /dev/null +++ b/brian2tools/templates/PopulationRateMonitor-default.md @@ -0,0 +1,5 @@ +{# Jinja2 template for PopRateMonitor in simple text format #} + +Monitors the population of {{ expander.expand_SpikeSource(group['source']) }}. + +{{ endll }} diff --git a/brian2tools/templates/PopulationRateMonitor-table.md b/brian2tools/templates/PopulationRateMonitor-table.md new file mode 100644 index 00000000..39c108df --- /dev/null +++ b/brian2tools/templates/PopulationRateMonitor-table.md @@ -0,0 +1,4 @@ +{# Jinja2 template for PopRateMonitor in table format #} + +|-------------------------------|--------------------------------------------------| +| **Monitored Population** | {{ expander.expand_SpikeSource(group['source']) }} | diff --git a/brian2tools/templates/SpikeGeneratorGroup-default.md b/brian2tools/templates/SpikeGeneratorGroup-default.md new file mode 100644 index 00000000..1aa7dd4d --- /dev/null +++ b/brian2tools/templates/SpikeGeneratorGroup-default.md @@ -0,0 +1,18 @@ +{# Basic information about the SpikeGeneratorGroup #} +{{ tab }}Name {{ (group['name']) }}, +with population size {{ (group['N']) }}, +has neuron{{ 's' if group['indices']|length > 1 else '' }}: +{{ expander.prepare_array(group['indices']) }} +that spike at times +{{ expander.prepare_array(group['times']) }}, +with period {{ group['period'] }}. +{{ endll }} + +{# Check for the 'run_regularly' key and expand if it exists #} +{% if 'run_regularly' in group %} + {{ tab }}{{ ('Run regularly:') }} + {{ endll }} + {% for run_reg in group['run_regularly'] %} + {{ expander.expand_runregularly(run_reg) }} + {% endfor %} +{% endif %} diff --git a/brian2tools/templates/SpikeGeneratorGroup-table.md b/brian2tools/templates/SpikeGeneratorGroup-table.md new file mode 100644 index 00000000..38e7fa17 --- /dev/null +++ b/brian2tools/templates/SpikeGeneratorGroup-table.md @@ -0,0 +1,9 @@ +{# Jinja2 template for SpikeGeneratorGroup in table format #} + +|-------------------------------|------------------------------------------------| +| **Name** | {{ group['name'] }} | +| **Population Size** | {{ group['N'] }} | +| **Neurons** | {{ expander.prepare_array(group['indices']) }} | +| **Spike Times** | {{ expander.prepare_array(group['times']) }} | +| **Period** | {{ group['period'] }} | +| **Run Regularly** (if present) | {% if 'run_regularly' in group %} {% for run_reg in group['run_regularly'] %} {{ expander.expand_runregularly(run_reg) }}{% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} | diff --git a/brian2tools/templates/SpikeMonitor-default.md b/brian2tools/templates/SpikeMonitor-default.md new file mode 100644 index 00000000..37ce18fa --- /dev/null +++ b/brian2tools/templates/SpikeMonitor-default.md @@ -0,0 +1 @@ +{%extends "EventMonitor-default.md" %} \ No newline at end of file diff --git a/brian2tools/templates/SpikeMonitor-table.md b/brian2tools/templates/SpikeMonitor-table.md new file mode 100644 index 00000000..956d4d84 --- /dev/null +++ b/brian2tools/templates/SpikeMonitor-table.md @@ -0,0 +1 @@ +{%extends "EventMonitor-table.md" %} diff --git a/brian2tools/templates/StateMonitor-default.md b/brian2tools/templates/StateMonitor-default.md new file mode 100644 index 00000000..96478707 --- /dev/null +++ b/brian2tools/templates/StateMonitor-default.md @@ -0,0 +1,9 @@ +{# Jinja2 template for Statemon in simple text format #} +Monitors variable{{ expander.check_plural(group['variables']) }}: {%- for var in group['variables'] -%} + {{ expander.render_expression(var) }}{%- if not loop.last -%}, {%- endif -%} +{%- endfor %} of {{ expander.expand_SpikeSource(group['source']) }} {%- if group['record'] is boolean -%} + {%- if group['record'] -%} for all members {%- else -%} for no member {%- endif -%} +{%- else -%} + {%- if group['record']|length == 0 -%} for no member {%- else -%} for member{{ expander.check_plural(group['record']) }}: {{ group['record'] | join(', ') }} {%- endif -%} +{%- endif -%} + diff --git a/brian2tools/templates/StateMonitor-table.md b/brian2tools/templates/StateMonitor-table.md new file mode 100644 index 00000000..4e8f39e5 --- /dev/null +++ b/brian2tools/templates/StateMonitor-table.md @@ -0,0 +1,10 @@ +| **Monitors** | **Variables** | **Source** | **Record** | +|-----------------|------------------------------------------------------------------------------------------------------------|-----------------------------------------------------|------------------------------------------------------------------------------------------------------------| +| Monitors variable{{ expander.check_plural(group['variables']) }}: {%- for var in group['variables'] -%} + {{ expander.render_expression(var) }}{%- if not loop.last -%}, {%- endif -%} +{%- endfor %} | of {{ expander.expand_SpikeSource(group['source']) }} | + {%- if group['record'] is boolean -%} + {%- if group['record'] -%} for all members {%- else -%} for no member {%- endif -%} + {%- else -%} + {%- if group['record']|length == 0 -%} for no member {%- else -%} for member{{ expander.check_plural(group['record']) }}: {{ group['record'] | join(', ') }} {%- endif -%} + {%- endif -%} | diff --git a/brian2tools/templates/Synapses-default.md b/brian2tools/templates/Synapses-default.md new file mode 100644 index 00000000..f20b6395 --- /dev/null +++ b/brian2tools/templates/Synapses-default.md @@ -0,0 +1,31 @@ +Connections {{ group['name'] }}, connecting {{ expander.expand_SpikeSource(group['source']) }} to {{ expander.expand_SpikeSource(group['target']) }} +{% if not expander.keep_initializer_order and 'connectors' in group and group['connectors']|length -%} + {{ tab }}{{ expander.expand_connector(group['connectors'][0]) }} +{% endif %} +{% if 'equations' in group -%} + {{ tab }}{{ bold('Model dynamics:') }} + {{ expander.expand_equations(group['equations']) }} + {% if 'user_method' in group -%} + {{ tab }}The equations are integrated with the '{{ group['user_method'] }}' method.{{ endll }} + {% endif %} +{% endif %} +{% if 'pathways' in group -%} + {{ expander.expand_pathways(group['pathways']) }} + {% if 'equations' not in group and 'identifiers' in group -%} + {{ tab }}, where {{ expander.expand_identifiers(group['identifiers']) }}. + {% endif %} +{% endif %} +{% if 'summed_variables' in group -%} + {{ tab }}{{ bold('Summed variables:') }} + {{ expander.expand_summed_variables(group['summed_variables']) }} +{% endif %} +{% if 'identifiers' in group and 'equations' in group -%} + {{ tab }}{{ bold('Constants:') }} {{ expander.expand_identifiers(group['identifiers']) }} +{% endif %} +{% if not expander.keep_initializer_order and 'initializer' in group and group['initializer']|length -%} + {{ tab }}{{ bold('Initial values:') }} + {% for initializer in group['initializer'] -%} + {{ tab }}* {{ expander.expand_initializer(initializer) }} + {% endfor %} +{% endif %} + diff --git a/brian2tools/templates/Synapses-table.md b/brian2tools/templates/Synapses-table.md new file mode 100644 index 00000000..d96f6f5d --- /dev/null +++ b/brian2tools/templates/Synapses-table.md @@ -0,0 +1,9 @@ +|-------------------------------|------------------------------------------------| +| **Connections** | {{ group['name'] }}, connecting {{ expander.expand_SpikeSource(group['source']) }} to {{ expander.expand_SpikeSource(group['target']) }} | +| **Connector** (if present) | {% if not expander.keep_initializer_order and 'connectors' in group and group['connectors']|length %} {{ expander.expand_connector(group['connectors'][0]) }} {% endif %} | +| **Model dynamics** (if present)| {% if 'equations' in group %} {% for key, eqn in group['equations'].items() %} $\frac{d}{d t} {{ key }}$ = {{ eqn.expr }}{% if eqn.unit %} [{{ eqn.unit }}]{% endif %} {% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} | +| **Integration method** (if present) | {% if 'user_method' in group %} The equations are integrated with the '{{ group['user_method'] }}' method. {% endif %} | +| **Pathways** (if present) | {% if 'pathways' in group %} {{ expander.expand_pathways(group['pathways']) }} {% if 'equations' not in group and 'identifiers' in group %} , where {{ expander.expand_identifiers(group['identifiers']) }}. {% endif %} {% endif %} | +| **Summed variables** (if present) | {% if 'summed_variables' in group %} {{ expander.expand_summed_variables(group['summed_variables']) }} {% endif %} | +| **Constants** (if present) | {% if 'identifiers' in group and 'equations' in group %} {% for identifier, value in group['identifiers'].items() %} {{ identifier }}: {{ value }} {% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} | +| **Initial values** (if present) | {% if not expander.keep_initializer_order and 'initializer' in group and group['initializer']|length %} {% for initializer in group['initializer'] %} {{ initializer.variable }}: {{ initializer.value }}{% if initializer.unit %} [{{ initializer.unit }}]{% endif %} {% if not loop.last %}\n{% endif %}{% endfor %} {% endif %} |