@@ -364,6 +364,61 @@ Sections
364364 The ``nrn_Item*`` returned can be used for loops in the same way as the ``all_sections`` variable in
365365 the example in :c:func:`nrn_allsec`.
366366
367+ .. c:function:: Section* nrn_section_parent(Section* sec)
368+
369+ Return the Section that ``sec`` is connected to, or ``NULL`` if ``sec`` is a
370+ root.
371+
372+ This is the direct connectivity, the same Section a HOC ``SectionRef``'s
373+ ``parent`` yields. It reads the connectivity directly, without creating a
374+ ``SectionRef`` object.
375+
376+ :param sec: The Section whose parent is wanted.
377+ :returns: The parent Section, or ``NULL`` if ``sec`` has no parent (or is
378+ ``NULL ``).
379+
380+ .. c:function:: Section* nrn_section_trueparent(Section* sec)
381+
382+ Return the *true* parent of ``sec``, or ``NULL`` if there is none.
383+
384+ The true parent (``SectionRef ``'s ``trueparent ``) is normally the parent,
385+ but a Section connected to the ``0`` end of its parent shares that parent's
386+ true parent, so the relationship climbs until a connection that is not at
387+ the parent's beginning.
388+
389+ :param sec: The Section whose true parent is wanted.
390+ :returns: The true parent Section, or ``NULL`` if there is none (or ``sec ``
391+ is ``NULL ``).
392+
393+ .. c:function:: Section* nrn_section_child(Section* sec)
394+
395+ Return the first child Section connected to ``sec``, or ``NULL`` if it has
396+ none.
397+
398+ Walk the remaining children with :c:func:`nrn_section_sibling`. The order
399+ matches ``SectionRef``'s ``child[i]``.
400+
401+ :param sec: The parent Section.
402+ :returns: The first child Section, or ``NULL`` (also if ``sec `` is ``NULL ``).
403+
404+ .. c:function:: Section* nrn_section_sibling(Section* sec)
405+
406+ Return the next Section that shares ``sec``'s parent, or ``NULL`` if ``sec``
407+ is the last child.
408+
409+ Paired with :c:func:`nrn_section_child`, this iterates every child of a
410+ Section:
411+
412+ .. code-block:: c
413+
414+ for (Section* c = nrn_section_child(parent); c; c = nrn_section_sibling(c)) {
415+ printf ("%s\n ", nrn_secname (c));
416+ }
417+
418+ :param sec: A Section.
419+ :returns: The next sibling Section, or ``NULL `` (also if ``sec `` is
420+ ``NULL ``).
421+
367422.. c :function :: bool nrn_section_is_active (const Section* sec)
368423
369424 Check if a Section is active (exists and is valid).
@@ -668,6 +723,112 @@ Segments
668723 seg.g_pas = 0.001 # S/cm²
669724
670725
726+ .. c :function :: int nrn_setpointer_pop (Symbol* pointer_sym, Section* sec, double x, char* error_msg, size_t error_msg_size)
727+
728+ Wire an NMODL ``POINTER`` variable to the source pointer on top of the stack.
729+
730+ The source is whatever pointer the caller has pushed, e.g. with
731+ :c:func:`nrn_rangevar_push`. Pushing the source rather than naming it lets
732+ this single function accept a pointer obtained any way the stack supports,
733+ instead of enumerating source kinds. The pushed pointer is consumed (popped)
734+ even on the error paths, so the stack is left balanced.
735+
736+ :param pointer_sym: Symbol of the ``POINTER`` range variable to wire (the
737+ target).
738+ :param sec: Section of the mechanism instance owning the POINTER.
739+ :param x: Normalized position (0.0 to 1.0) of that instance.
740+ :param error_msg: Buffer filled with a message on failure (may be ``NULL ``).
741+ :param error_msg_size: Size of ``error_msg``.
742+ :returns: 0 on success; nonzero on error, with ``error_msg`` populated when
743+ ``pointer_sym`` is not a ``POINTER `` variable or its mechanism is not
744+ present at the target segment.
745+
746+ This addresses the target by ``(sec, x) ``, which identifies a density
747+ mechanism's single instance at a segment. For a **point process **, where
748+ several instances may share one location, use
749+ :c:func: `nrn_pp_setpointer_pop `, which addresses the target by instance
750+ object instead.
751+
752+ This is the C-API equivalent of the HOC ``setpointer `` statement and of
753+ assigning a ``_ref_ `` to a POINTER in Python. It stores a data handle to the
754+ source, so the connection survives internal data reordering.
755+
756+ **C Usage: **
757+
758+ .. code-block :: c
759+
760+ // A density mechanism `cufl` has a POINTER `pv`. Wire dend's instance to
761+ // read soma(0.5).v instead of its own segment's voltage. A density
762+ // mechanism has one instance per segment, so (dend, 0.5) names it.
763+ Symbol* pv = nrn_symbol("pv_cufl");
764+ Symbol* v = nrn_symbol("v");
765+ char err[256];
766+ nrn_rangevar_push(v, soma, 0.5); // push the source pointer
767+ if (nrn_setpointer_pop(pv, dend, 0.5, err, sizeof(err))) {
768+ fprintf(stderr, "setpointer failed: %s\n", err);
769+ }
770+
771+ **Python Equivalent: **
772+
773+ .. code-block :: python
774+
775+ # cufl is a density mechanism (SUFFIX) with a POINTER pv
776+ dend(0.5 ).cufl._ref_pv = soma(0.5 )._ref_v
777+
778+ .. seealso ::
779+
780+ :c:func: `nrn_pp_setpointer_pop `, :c:func: `nrn_rangevar_push `
781+
782+ .. c :function :: int nrn_pp_setpointer_pop (Object* pp, const char* name, char* error_msg, size_t error_msg_size)
783+
784+ Wire a point process's NMODL ``POINTER`` variable to the source pointer on
785+ top of the stack.
786+
787+ This is the point-process counterpart to :c:func:`nrn_setpointer_pop`. A
788+ point process is addressed by its instance object rather than by ``(sec,
789+ x)``: several point processes may occupy one location (two half-gaps at one
790+ segment, say), so the segment alone cannot identify which instance owns the
791+ ``POINTER`` slot. The ``POINTER`` is named within the point process's own
792+ symbol table, exactly as in :c:func:`nrn_property_get`.
793+
794+ As with :c:func:`nrn_setpointer_pop`, the source is whatever pointer the
795+ caller has pushed (e.g. with :c:func: `nrn_rangevar_push ` or
796+ :c:func: `nrn_property_push `), and it is consumed even on the error paths, so
797+ the stack is left balanced.
798+
799+ :param pp: The point process instance whose ``POINTER`` is the target.
800+ :param name: Name of the ``POINTER`` variable within the point process.
801+ :param error_msg: Buffer filled with a message on failure (may be ``NULL ``).
802+ :param error_msg_size: Size of ``error_msg``.
803+ :returns: 0 on success; nonzero on error, with ``error_msg`` populated when
804+ ``pp`` is not a point process, ``name`` is not one of its ``POINTER ``
805+ variables, or the point process is not located in a section.
806+
807+ **C Usage: **
808+
809+ .. code-block :: c
810+
811+ // Wire a half-gap point process's vgap POINTER to the peer cell's
812+ // voltage: cell2's membrane potential drives the gap current the
813+ // HalfGap instance on cell1 computes. A true half gap wires both ways.
814+ char err[256];
815+ nrn_rangevar_push(nrn_symbol("v"), cell2, 0.5); // push the source pointer
816+ if (nrn_pp_setpointer_pop(halfgap1, "vgap", err, sizeof(err))) {
817+ fprintf(stderr, "setpointer failed: %s\n", err);
818+ }
819+
820+ **Python Equivalent: **
821+
822+ .. code-block :: python
823+
824+ # halfgap1 is a POINT_PROCESS instance with a POINTER vgap
825+ halfgap1._ref_vgap = cell2(0.5 )._ref_v
826+
827+ .. seealso ::
828+
829+ :c:func: `nrn_setpointer_pop `, :c:func: `nrn_property_push `, :c:func: `nrn_rangevar_push `
830+
831+
671832Functions, objects, and the stack
672833---------------------------------
673834
0 commit comments