Skip to content

Defining a C API #2002

Description

@ramcdougal

This is a work in progress

Overview

Broad design decisions: Presumably we want an interface that is compact but full-featured (this means using the stack machine to call finitialize rather than providing access to the underlying finitialize code itself). What we do needs to be extern "C". There should be some consistency in the interface; in 8.2, some of these things are prefaced by nrn, others by hoc, others are clearly helper functions for other functions that we don't use (e.g. hoc_newobj1 and ob2pntproc_0).

Well... I don’t think we want to just extern "C" things that already exist… I think we need to have the right access points so the API is detached from details of memory management etc

Working example of using NEURON and C++ to compute an action potential: demo2.cpp

Working example of configuring morphology and topology via C++: morphology-demo.cpp

Initialization

Not extern "C" in 8.2, but needed:

  • nrnmpi_stubs (required with dynamic MPI)
  • ivocmain_session (required always)
    • should this be refactored to have a function that just initializes but doesn't have an option of starting the REPL?

Redirecting stdout/stderr in 8.2 (needed so we don't print to the terminal) requires setting the nrn_is_python_extension flag, e.g.

    int old_python_flag = *((int*) dlsym(handle, "nrn_is_python_extension"));
    *((int*) dlsym(handle, "nrn_is_python_extension")) = 1;
    nrnpy_set_pr_etal(myprint, NULL);
    *((int*) dlsym(handle, "nrn_is_python_extension")) = old_python_flag;

Should we remove this limitation or add another function without it?

Core stack machine access

These functions need to remain extern "C" (or some version of them, anyways):

Calling functions, class constructors, and methods:

  • hoc_call_func -- call a function
  • hoc_newobj1 -- create an object
  • hoc_lookup -- lookup a top-level symbol
  • hoc_table_lookup -- lookup a symbol for a class method etc
  • call_ob_proc -- call a method

Pushing arguments to the stack, getting return values:

  • hoc_pushx and hoc_xpop -- for doubles
  • hoc_pushstr and hoc_strpop -- for char**
  • hoc_pushobj and hoc_objpop -- for Object**
    • there's a note in src/oc/code.cpp that we should call hoc_tobj_unref(pobj) to prevent memory leakage when done dealing with an Object pointer
  • hoc_pushpx -- for pointers (but note NEURON 9.0 is planning on changing how pointers are done)

Updating the section stack (necessary so e.g. IClamp objects are put in the right section):

  • nrn_pushsec -- strongly advising always pairing with a pop
  • nrn_popsec

Model configuration

  • new_sections -- create a section; to create a named section, construct a Symbol* of type 1 with the name, register the name via hoc_install_object_data_index, and then pass the symbol to new_sections
  • ob2pntproc_0 -- converts an Object* to a Point_process*, which allows getting and setting point process properties
  • simpleconnectsection -- connect sections
    • this requires things to be pushed to both the stack and the section stack; would probably be better to refactor
  • mech_insert1 -- inserting a distributed mechanism
  • nrn_rangepointer -- get pointers to range variables (needed to setup recording)
  • nrn_length_change -- must be called when length changed and 3d points exist; safe to call regardless

Miscellaneous and important

  • node_exact -- return a Node* (think Segment) from a Section and x value

Global variables

  • nrn_main_launch
  • nrn_nobanner -- block the display of a banner
  • diam_changed -- needs to be set when the geometry is changed (not just the diameter)
  • nrn_is_python_extension -- telling it no stops NEURON from trying to load Python libraries
  • hoc_build_in_symlist and hoc_top_level_symlist -- list of Symbols; necessary to dynamically generate interface

Reference counting:

  • ???

Calling HOC directly:

(can fill in any gaps in the interface until resolved)

  • hoc_oc

Data type definitions needed

  • Symbol -- used everywhere
  • Point_process -- returned by ob2pntproc_0, allows accessing point process properties
  • Prop -- part of Point_process on path toward point process properties
  • Datum -- part of Prop on path toward point process properties
  • Object -- used everywhere, allows accessing cTemplate to get class-specific methods
  • cTemplate -- used with hoc_table_lookup for calling class-specific methods, can also be used to list the methods and types
  • hoc_Item -- part of process of creating a new Section
  • Section -- allows direct access to e.g. 3D points, but unclear if it would suffice to make this just an opaque pointer

Special functions

Vectors are so useful, we really do want to be able to access them as a double*

  • vector_capacity -- the length (?) of a Vector
  • vector_vec -- the double*
  • secname -- useful for debugging, introspection

Not yet sure how to do

  • getting/setting section properties without needing to know internals (e.g. that Ra is sec->prop->dparam[7] and length is sec->prop->dparam[2])
  • getting/setting object properties (for objects that aren't point processes)

Documentation will be needed for all of this

  • Do we want to rename the functions from hoc_ to e.g. nrn_ since not really about HOC per se?

Foreseeable Impact

  • Possible benefits
    • ease of adding new interfaces to NEURON
  • Area(s) of change: C/C++
  • Possible issues:
    • need to keep small to maintain ability to take advantage of C++ features
    • 9.0? plans for changes to pointers

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions