@@ -44,7 +44,9 @@ Phase B contract
4444- ``NET_RECEIVE `` mechanism computation on GPU during the step
4545- CPU spike priority queues + MPI exchange at the minimum NetCon delay interval
4646- GPU ``net_send `` buffering; cross-cell events to CPU/MPI; self-events may flush on device
47- - Gap junctions: device voltage pull, sparse MPI transfer, host fallback where required
47+ - Gap junctions: **correctness ** on native GPU when ``pc.setup_transfer() `` is
48+ active; fixed-step integration runs the **CPU body ** (full fallback) until
49+ device partrans gather/scatter is implemented
4850- Batch host download API for ``Vector.record `` and graphs (``download_flush_interval ``)
4951
5052**Out of scope (deferred) **
@@ -76,7 +78,7 @@ Supported and unsupported matrix
7678+-------------------------------+------------------+---------------------------+
7779| ``net_send `` self-events | GPU buffer | May flush on device |
7880+-------------------------------+------------------+---------------------------+
79- | Gap junctions | Supported | Sparse MPI voltage/ion |
81+ | Gap junctions | Supported | CPU fixed-step fallback |
8082+-------------------------------+------------------+---------------------------+
8183| ``Vector.record `` | Supported | Batch download API |
8284+-------------------------------+------------------+---------------------------+
@@ -154,8 +156,8 @@ not a rewrite of the whole native path.
154156+---------------------------+--------------------+-------------------------------+
155157| ``net_send `` buffer | GPU | GPU-capable in principle |
156158+---------------------------+--------------------+-------------------------------+
157- | Gap junction transfer | See gap phases | Same (if gaps present) |
158- | (``setup_transfer ``) | below | |
159+ | Gap junction transfer | ** CPU fixed-step | Same (if gaps present) |
160+ | (``setup_transfer ``) | fallback** (below) | |
159161+---------------------------+--------------------+-------------------------------+
160162| Recording flush | GPU → host batch | Same API |
161163+---------------------------+--------------------+-------------------------------+
@@ -176,21 +178,22 @@ limitations (see matrix above).
176178.. mermaid ::
177179
178180 flowchart TD
179- A[CPU: deliver_net_events] --> B[GPU: setup_tree_matrix + NMODL currents]
181+ S{nrnthread_v_transfer _ registered?}
182+ S -->|yes| CPUALL[CPU fixed-step: deliver, matrix, solve, update, gap transfer, lastpart]
183+ S -->|no| A[CPU: deliver_net_events]
184+ A --> B[GPU: setup_tree_matrix + NMODL currents]
180185 B --> C[GPU: tree solve solve_interleaved]
181186 C --> D{post_solve host fallback?}
182187 D -->|no| E[GPU: post_solve V, fast_imem, capacity]
183188 D -->|yes| F[CPU: post_solve nrn_update_voltage]
184- E --> G{gap transfer configured?}
185- F --> G
186- G -->|yes| H[CPU: gap gather, MPI if nhost>1, scatter in lastpart]
187- G -->|no| I[GPU: lastpart NET_RECEIVE + nonvint + vecplay]
188- H --> I
189+ E --> I[GPU: lastpart NET_RECEIVE + nonvint + vecplay]
190+ F --> I
189191 I --> J{download flush interval?}
190192 J -->|yes| K[batch_download_to_host]
191193 J -->|no| L[defer to next flush / psolve end]
192194 K --> M[advance step counter]
193195 L --> M
196+ CPUALL --> M
194197
195198On this path ``nt.compute_gpu `` is set for integration. NMODL ``BREAKPOINT ``
196199currents (``nrn_cur_* `` OpenACC) and OpenACC axial assembly in ``setup_tree_matrix ``
@@ -202,12 +205,22 @@ run on the GPU. **GPU tree solve** is ``solve_interleaved`` / ``solve_interleave
202205during **lastpart ** (after the solve/post-solve block). Cross-rank spike
203206**scheduling ** remains on CPU (see spike policy in :doc: `gpu-testing `).
204207
205- **Gap junction transfer ** (``ParallelContext.setup_transfer ``) is ** not ** gated on
206- MPI or `` pc.nthread(n)>1 `` alone. The diamond is true whenever
207- `` nrnthread_v_transfer_ `` is registered (gap junctions or other partrans targets) —
208- including single-process, single-thread models with gaps .
208+ **Gap junction transfer ** (``ParallelContext.setup_transfer ``) registers
209+ `` nrnthread_v_transfer_ `` whenever partrans targets exist — including
210+ single-process, single-thread models with gaps (not only when MPI or
211+ `` pc.nthread(n)>1 ``) .
209212
210- On CPU fixed-step, partrans uses three conceptual phases (``partrans.cpp ``):
213+ Phase B native GPU **does not ** run the hybrid GPU integration path above when
214+ ``nrnthread_v_transfer_ `` is set. ``nrn_fixed_step_thread `` in ``fadvance.cpp ``
215+ dispatches the **full CPU fixed-step body ** instead of ``fadvance_gpu.cpp `` until
216+ device-resident partrans gather/scatter is complete. ``gpu.enable=True `` still
217+ uploads mechanisms and state to device, but matrix setup, solve, post-solve, gap
218+ transfer, and lastpart execute on the CPU for correctness (validated by
219+ ``test/gjtests/test_par_gj_native_gpu.py `` and ringtest ``-gap ``). Runtime is
220+ therefore ~1× NEURON CPU for gap models, not the slower hybrid path seen on
221+ non-gap workloads.
222+
223+ On that CPU path, partrans uses three phases (``partrans.cpp ``):
211224
2122251. **Gather ** source values into transfer buffers (``mpi_transfer ``: ``outsrc_buf_[i]
213226 = *poutsrc_[i] ``).
@@ -216,12 +229,11 @@ On CPU fixed-step, partrans uses three conceptual phases (``partrans.cpp``):
2162293. **Scatter ** to targets (``thread_transfer `` in ``nonvint ``, per thread:
217230 ``*(ttd.tv[i]) = *(ttd.sv[i]) ``).
218231
219- Phase B native GPU: after post-solve, ``sync_gap_after_voltage_update `` pulls source
220- voltages **GPU → host ** so phase 1 can read them; thread 0 runs ``nrnmpi_v_transfer_ ``
221- (MPI phase 2 when multi-rank); phase 3 still runs on the **CPU ** inside lastpart
222- ``nonvint ``. Gather and scatter are not on device yet — a future optimization could
223- keep phases 1 and 3 on GPU and avoid host staging when **no MPI ** (and possibly for
224- intra-node thread transfers), but that is outside Phase B.
232+ A future optimization would restore the GPU integration subphases and move phases
233+ 1 and 3 to device buffers, touching host/MPI only when ``nrnmpi_numprocs > 1 ``.
234+ The hybrid sync helpers in ``sync.cpp `` (``sync_gap_after_voltage_update ``,
235+ ``sync_gap_after_host_voltage_update ``) remain for that path; they are not used on
236+ the Phase B CPU fallback dispatch.
225237
226238For DAE models, only the **matrix solve ** subphase must swap to CPU ``sparse13 ``;
227239other subphases are not inherently excluded by the subphase design, but Phase B
0 commit comments