From 4ce1bc78d0d307c765ffd8e7dace11ea6832af10 Mon Sep 17 00:00:00 2001 From: Pooja Babu Date: Wed, 15 Oct 2025 12:42:31 +0200 Subject: [PATCH 1/2] Fix synapse bug when the model uses both third factor and neuromodulated spikes --- .../common/SynapseHeader.h.jinja2 | 39 ++++++++++++++++--- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 index b3cd2142b..17bf7cdab 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 @@ -1027,9 +1027,11 @@ void {%- filter indent(4, True) %} {%- set dynamics = synapse.get_on_receive_block(vt_port) %} -{%- with ast = dynamics.get_stmts_body() %} -{%- include "directives_cpp/StmtsBody.jinja2" %} -{%- endwith %} +{%- if dynamics is not none %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} +{%- endwith %} +{%- endif %} {%- endfilter %} // process remaining dopa spikes in (t0, t1] double cd; @@ -1047,9 +1049,11 @@ void **/ {%- filter indent(6, True) %} {%- set dynamics = synapse.get_on_receive_block(vt_port) %} -{%- with ast = dynamics.get_stmts_body() %} -{%- include "directives_cpp/StmtsBody.jinja2" %} -{%- endwith %} +{%- if dynamics is not none %} +{%- with ast = dynamics.get_stmts_body() %} +{%- include "directives_cpp/StmtsBody.jinja2" %} +{%- endwith %} +{%- endif %} {%- endfilter %} /** @@ -1398,6 +1402,16 @@ inline void std::deque< histentry__{{ paired_neuron_name }} >::iterator start; std::deque< histentry__{{ paired_neuron_name }} >::iterator finish; static_cast<{{ paired_neuron_name }}*>(get_target(t))->get_history__( t_last_update_ - dendritic_delay, t_trig - dendritic_delay, &start, &finish ); +{%- if paired_neuron_name is not none and paired_neuron_name|length > 0 and paired_neuron.state_vars_that_need_continuous_buffering | length > 0 and continuous_state_buffering_method == "continuous_time_buffer" %} + // get continuous-time history entries in relevant range (t1, t2] from post-synaptic neuron + std::deque< continuous_variable_histentry_{{ paired_neuron_name }} >::iterator continuous_history_start; + std::deque< continuous_variable_histentry_{{ paired_neuron_name }} >::iterator continuous_history_finish; + + ((post_neuron_t*)(get_target(t)))->get_continuous_variable_history( t_last_update_, + t_trig, + &continuous_history_start, + &continuous_history_finish ); +{%- endif %} // facilitation due to postsyn. spikes since last update double t0 = t_last_update_; @@ -1415,6 +1429,19 @@ inline void std::cout << "[synapse " << this << "] {{ synapseName }}: processing post spike from " << t_last_update_ << " to " << start->t_ + dendritic_delay << std::endl; #endif +{%- if paired_neuron_name is not none and paired_neuron_name|length > 0 and paired_neuron.state_vars_that_need_continuous_buffering | length > 0 %} + continuous_variable_histentry_{{ paired_neuron_name }} histentry(0., +{%- for state_var in paired_neuron.state_vars_that_need_continuous_buffering %} + {{ state_vars_that_need_continuous_buffering_transformed_iv[state_var] }}{% if not loop.last %},{% endif %} +{%- endfor %}); + get_entry_from_continuous_variable_history(start->t_ + dendritic_delay, continuous_history_start, continuous_history_finish, histentry); + +{%- for var_name in paired_neuron.state_vars_that_need_continuous_buffering %} +{%- set var = utils.get_parameter_variable_by_name(astnode, var_name) %} + const double __{{ var_name }} = histentry.{{ var_name }}; +{%- endfor %} +{%- endif %} + /** * update synapse internal state from `t_last_update_` to `start->t_ + dendritic_delay` **/ From 81e88aaf3a9cb96f0c0dd261a8b0e8fef5499645 Mon Sep 17 00:00:00 2001 From: "C.A.P. Linssen" Date: Wed, 15 Oct 2025 13:05:29 +0200 Subject: [PATCH 2/2] slight refactoring --- .../common/SynapseHeader.h.jinja2 | 31 ++++++++++++++----- 1 file changed, 23 insertions(+), 8 deletions(-) diff --git a/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 b/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 index 17bf7cdab..c11f82811 100644 --- a/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 +++ b/pynestml/codegeneration/resources_nest/point_neuron/common/SynapseHeader.h.jinja2 @@ -1402,8 +1402,14 @@ inline void std::deque< histentry__{{ paired_neuron_name }} >::iterator start; std::deque< histentry__{{ paired_neuron_name }} >::iterator finish; static_cast<{{ paired_neuron_name }}*>(get_target(t))->get_history__( t_last_update_ - dendritic_delay, t_trig - dendritic_delay, &start, &finish ); -{%- if paired_neuron_name is not none and paired_neuron_name|length > 0 and paired_neuron.state_vars_that_need_continuous_buffering | length > 0 and continuous_state_buffering_method == "continuous_time_buffer" %} - // get continuous-time history entries in relevant range (t1, t2] from post-synaptic neuron + +{%- if paired_neuron_name is not none and paired_neuron_name|length > 0 and paired_neuron.state_vars_that_need_continuous_buffering | length > 0 %} + +{%- if continuous_state_buffering_method != "continuous_time_buffer" %} +{{ raise('In combination with a volume transmitter input port, only ``"continuous_time_buffer"`` is supported for ``continuous_state_buffering_method`` code generator option.') }} +{%- endif %} + + // get continuous-time history entries in relevant range (t_last_update, t_trig] from post-synaptic neuron std::deque< continuous_variable_histentry_{{ paired_neuron_name }} >::iterator continuous_history_start; std::deque< continuous_variable_histentry_{{ paired_neuron_name }} >::iterator continuous_history_finish; @@ -1421,7 +1427,7 @@ inline void while ( start != finish ) { {%- for vt_port in vt_ports %} -{%- set vt_port = vt_ports[0] %} +{%- set vt_port = vt_ports[0] %} process_{{vt_port}}_spikes_( vt_spikes, t0, start->t_ + dendritic_delay, cp ); {%- endfor %} @@ -1430,16 +1436,25 @@ inline void #endif {%- if paired_neuron_name is not none and paired_neuron_name|length > 0 and paired_neuron.state_vars_that_need_continuous_buffering | length > 0 %} + +{%- if continuous_state_buffering_method != "continuous_time_buffer" %} +{{ raise('In combination with a volume transmitter input port, only ``"continuous_time_buffer"`` is supported for ``continuous_state_buffering_method`` code generator option.') }} +{%- endif %} + +#ifdef DEBUG + std::cout << "Grabbing continuous_variable_history at t = " << start->t_ + dendritic_delay << "\n"; +#endif + continuous_variable_histentry_{{ paired_neuron_name }} histentry(0., {%- for state_var in paired_neuron.state_vars_that_need_continuous_buffering %} {{ state_vars_that_need_continuous_buffering_transformed_iv[state_var] }}{% if not loop.last %},{% endif %} -{%- endfor %}); +{%- endfor %}); get_entry_from_continuous_variable_history(start->t_ + dendritic_delay, continuous_history_start, continuous_history_finish, histentry); -{%- for var_name in paired_neuron.state_vars_that_need_continuous_buffering %} -{%- set var = utils.get_parameter_variable_by_name(astnode, var_name) %} - const double __{{ var_name }} = histentry.{{ var_name }}; -{%- endfor %} +{%- for var_name in paired_neuron.state_vars_that_need_continuous_buffering %} +{%- set var = utils.get_parameter_variable_by_name(astnode, var_name) %} + const double __{{ var_name }} = histentry.{{ var_name }}; +{%- endfor %} {%- endif %} /**