Accessing External libraries though include or exec()

The basics of how to develop, test, and use models.
Post Reply
aluchko

Accessing External libraries though include or exec()

Post by aluchko »

I was looking for a way I could access external code from a hoc file.

One option would be some kind of interface whereby I could include a C or other kind of library than call those functions through some kind of wrapper.

Another option would be something similar to an exec() whereby I could wrap my external library in a small program than send data back and forth through a pipe.

Unfortunately I haven't been able to find anything in the docs.


If there's no other option I could re-build neuron with the functions built in, or just write a program that drove its own instance of neuron, but I'd rather use one of the two approaches above.
ted
Site Admin
Posts: 6305
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Accessing External libraries though include or exec()

Post by ted »

The way to make external libraries available to hoc is by using a VERBATIM block in an NMODL file to add a new function to hoc. Take a look at the following threads and then tell me if you need further information.

Adding C code in a model file
http://www.neuron.yale.edu/phpBB/viewto ... =16&t=1194

How to access C function (random, srandom..) in NMODL files?
http://www.neuron.yale.edu/phpBB/viewto ... f=16&t=292
aluchko

Re: Accessing External libraries though include or exec()

Post by aluchko »

Thanks, I didn't see anything about VERBATIM in the docs but it works great.
ted
Site Admin
Posts: 6305
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Accessing External libraries though include or exec()

Post by ted »

Here's what I do when I'm looking for a particular topic or keyword but can't find it in the alphabetical index to the Programmer's Reference and don't know where to look in the "usual tutorials and other documentation"--
go to NEURON's WWW page http://www.neuron.yale.edu/ and do a Google search.

In the case of the word VERBATIM, searching for
VERBATIM -php
returns a bunch of hits, the second of which is to the Programmer's Reference page about NMODL. (the -php blocks out a bunch of stuff in the Forum)
http://www.neuron.yale.edu/neuron/stati ... nmodl.html
Buried in that page, near the very end, in the discussion of INITIAL, is this sentence:
Since NMODL produces a c file, it is possible for the highly motivated to modify that file in order to do something implementation dependent. In this regard, the VERBATIM block can be used to place c code within the model description file.
This feature allows NEURON to be used as a (very) "poor man's C development environment."
aluchko

Re: Accessing External libraries though include or exec()

Post by aluchko »

So I can write the C code I need in a mod, and I can call these C functions from a hoc.

But I then need to have that C code call a function I defined in a hoc file and I'm not sure how to do this.

Is there a way to call hoc functions from a MODL file?
hines
Site Admin
Posts: 1692
Joined: Wed May 18, 2005 3:32 pm

Re: Accessing External libraries though include or exec()

Post by hines »

Here is a small example you can modify by analogy. See nrn/src/ivoc/oc2iv.h for a list of useful
functions prototypes that deal with the interpreter.
I left out error checking in the example.
foo.hoc

Code: Select all

func foo() {
        return $1*$1
}

print bar(5)
print bar(10)
bar.mod

Code: Select all

NEURON { SUFFIX nothing }

VERBATIM
extern hoc_pushx(double);
extern double hoc_call_func(Symbol* sym, int narg);
extern Symbol* hoc_lookup(const char*);
ENDVERBATIM

FUNCTION bar(arg) {
VERBATIM {
        Symbol* s = hoc_lookup("foo");
        hoc_pushx(_larg);
        _lbar = hoc_call_func(s, 1);
}
ENDVERBATIM
}
aluchko

Re: Accessing External libraries though include or exec()

Post by aluchko »

I'm having some trouble passing a vector instead of a scalar.

foo.hoc

Code: Select all

func blah() {localobj lvec
	printf("args %g\n", numarg())
	print argtype(1)
	lvec=$o1
	return 1
}

objref vec
vec=new Vector(1)
vec.x[0]=1
testv(vec)
print vec.x[0]
testv.mod

Code: Select all

NEURON {
	POINTER vecP
	SUFFIX nothing
}

PARAMETER {
	vecP=0
}

VERBATIM
extern int vector_capacity(void* vv);
extern void* vector_arg(int iarg);
extern hoc_pushobj(Object**);
extern hoc_push_object(Object*);
extern hoc_pushx(double);
extern double hoc_call_func(Symbol* sym, int narg);
extern Symbol* hoc_lookup(const char*);

ENDVERBATIM

PROCEDURE testv() {
VERBATIM
        void** vv = (void**)_p_vecP;
//	void ** vv = vector_arg(1);
        int size = vector_capacity(vv);
        printf("setVec.size=%d\n",size);
        vv[0]=3;
        Symbol* s = hoc_lookup("blah");
//	hoc_pushobj(vv);
        hoc_push_object(&vv);
        hoc_call_func(s,1);

ENDVERBATIM
}
I'm able to access the Vect fine in testv(), but when I than try to access the object in blah() I get a segmentation fault. Ideally I'd like to be able to return a Vector from testv though the docs seem to indicate that only a double is possible (http://www.neuron.yale.edu/neuron/stati ... l#Function), however I could work around this latter limitation.
hines
Site Admin
Posts: 1692
Joined: Wed May 18, 2005 3:32 pm

Re: Accessing External libraries though include or exec()

Post by hines »

A good example of casting pointers in a mod file is in nrn/src/nrnoc/pattern.mod
The relevant idioms are

Code: Select all

        POINTER ptr
...
VERBATIM
#define VCAST void** vp = (void**)(&(_p_ptr))
...
PROCEDURE foo() {
VERBATIM
    VCAST; void* vec = *vp;
    vec = vector_arg(1);
...

aluchko

Re: Accessing External libraries though include or exec()

Post by aluchko »

hines, thanks for the pointer though I'm not sure what I'm supposed to be looking at in pattern.mod. I'm already able to cast the incoming argument to a vector, the problem is when I then try to pass the resulting Vector back to the hoc function blah() I get a segfault when I try to use the Vector in blah.

I tried modifying testv() to be more in line with the code you suggested but with no improvement

Code: Select all

PROCEDURE testv() {
VERBATIM
    VCAST; void* vec = *vp;
    vec = vector_arg(1);
    Symbol* s = hoc_lookup("blah");
    printf("vec is %i, vp is %i\n",vec,vp);
    hoc_push_object(vp);
    hoc_call_func(s,1);
ENDVERBATIM
One thing I don't quite understand is the use of void* vec= *vp.

*vp ends up being null in my code, though it looks like it could get set through things like _hoc_setdata. Either way I don't see the point in assigning vec = *vp only to reassign vec to vector_arg(1) in the very next line.
ted
Site Admin
Posts: 6305
Joined: Wed May 18, 2005 4:50 pm
Location: Yale University School of Medicine
Contact:

Re: Accessing External libraries though include or exec()

Post by ted »

The associated hoc code would help. Here's another example that might be useful:
nrn/examples/nrniv/netcon contains vecevent.hoc, vecevent.ses, and vecevent.mod

vecevent.ses is a session file that recreates a model constructed with the Network Builder. This model consists of a single instance of the VecStim class. The VecStim class is a class of artificial spiking cell whose spike times are specified by the elements in a Vector.

vecevent.hoc illustrates the usage of a VecStim object; here's the file with my comments:

Code: Select all

load_file("nrngui.hoc")
load_file("vecevent.ses") // the VecStim object will be called vs_VecStim[0]
objref evec
evec = new Vector(100) // will hold times at which the VecStim should generate an event
evec.indgen // evec's elements are now 0, 1 . . . 99
vs_VecStim[0].pp.play(evec) // the VecStim object generates events at t = 0, 1 . . . 99 ms
Here's vecevent.mod. Note how PROCEDURE play references the elements of evec.

Code: Select all

:  Vector stream of events

NEURON {
	ARTIFICIAL_CELL VecStim
}

ASSIGNED {
	index
	etime (ms)
	space
}

INITIAL {
	index = 0
	element()
	if (index > 0) {
		net_send(etime - t, 1)
	}
}

NET_RECEIVE (w) {
	if (flag == 1) {
		net_event(t)
		element()
		if (index > 0) {
			net_send(etime - t, 1)
		}
	}
}

VERBATIM
extern double* vector_vec();
extern int vector_capacity();
extern void* vector_arg();
ENDVERBATIM

PROCEDURE element() {
VERBATIM	
  { void* vv; int i, size; double* px;
	i = (int)index;
	if (i >= 0) {
		vv = *((void**)(&space));
		if (vv) {
			size = vector_capacity(vv);
			px = vector_vec(vv);
			if (i < size) {
				etime = px[i];
				index += 1.;
			}else{
				index = -1.;
			}
		}else{
			index = -1.;
		}
	}
  }
ENDVERBATIM
}

PROCEDURE play() {
VERBATIM
	void** vv;
	vv = (void**)(&space);
	*vv = (void*)0;
	if (ifarg(1)) {
		*vv = vector_arg(1);
	}
ENDVERBATIM
}
Post Reply