File: developer.html

package info (click to toggle)
libctl 3.2.2-2
  • links: PTS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 2,308 kB
  • ctags: 1,178
  • sloc: sh: 11,466; ansic: 5,903; lisp: 2,311; makefile: 123
file content (450 lines) | stat: -rw-r--r-- 17,680 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML><HEAD>
<TITLE>Developer Information</TITLE>
<LINK rel="Bookmark" title="libctl Manual" href="index.html">
<LINK rel="Bookmark" title="Ab Initio Physics Home Page"
      href="http://ab-initio.it.edu">
<LINK rel="Contents" href="index.html">
<LINK rel="Copyright" href="license.html">
<LINK rel="Start" href="index.html">
<LINK rel="Previous" href="user-ref.html">
<LINK rel="Next" href="developer.html">
</HEAD>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">

Go to the <a href="guile-links.html">next</a>, <a
href="user-ref.html">previous</a>, or <a href="index.html">main</a>
section.
<hr>

<h1>Developing a Program Using libctl</h1>

If you are thinking of using libctl in a program that you are writing,
you might be rolling your eyes at this point, thinking of all the work
that it will be.  A full programming language?  Complicated data
structures?  Information passing back and forth?  Surely, it will be a
headache to support all of these things.

<p>In fact, however, using libctl is much easier than writing your
program for a traditional, fixed-format input file.  You simply
describe in an abstract specifications file the variables and data
types that your program expects to exchange with the ctl file, and the
functions by which it is called.  From these specifications, code is
automatically generated to export and import the information to and
from Guile.

<p>The specifications file is written in Scheme, and consists of
definitions for the classes and input/output variables the program
expects.  It may also contain any predefined functions or variables
that might be useful in ctl files for the program, and says which
functions in your program are callable from the ctl script.

<h2>Defining input variables</h2>

To define an input variable (a variable specified by the ctl file and
input into the program), use the following construction:

<pre>
(define-input-var <i>name value type [ constraints ... ]</i>)
</pre>

<p>Here, <code><i>name</i></code> is the name of the variable, and
<code><i>value</i></code> is its initial value--so far, this is just
like a normal <code>define</code> statement.  However, input variables
have constraints on them, the simplest of which is that they have a
specific type.  The <code><i>type</i></code> parameter can be one of:

<ul>

<li><code>'number</code> - a real number

<li><code>'cnumber</code> - a complex number

<li><code>'integer</code> - an integer

<li><code>'vector3</code> - a real 3-vector

<li><code>'matrix3x3</code> - a real 3x3 matrix

<li><code>'cvector3</code> - a complex 3-vector

<li><code>'cmatrix3x3</code> - a complex 3x3 matrix

<li><code>'boolean</code> - a boolean value, <code>true</code> or
<code>false</code>

<li><code>'string</code> - a string

<li><code>'function</code> - a function (in C, a Guile SCM function pointer)

<li><code>'<i>class</i></code> - an member of <code><i>class</i></code>

<li><code>(make-list-type <i>el-type</i>)</code> - a list of elements
of type <code><i>el-type</i></code>

<li><code>'SCM</code> - a generic Scheme object

</ul>

<p>Note that the quote before a type name is Scheme's way of
constructing a <b>symbol</b>, which is somewhat similar to a C
enumerated constant.

<p>The final argument is an optional sequence of constraints.  Each
constraint is a function that, given a value, returns
<code>true</code> or <code>false</code> depending on whether that
value is valid.  For example, if an input variable is required to be
positive, one of the constraints would be the <code>positive?</code>
function (predefined by Guile).  More complicated functions can, of
course, be constructed.

<p>Here are a few examples:

<pre>
(define-input-var dimensions 3 'integer positive?)
(define-input-var default-epsilon 1.0 'number positive?)
(define-input-var geometry '() (make-list-type 'geometric-object))
(define-input-var k-points '() (make-list-type 'vector3))
</pre>

<p>Notice that all input variables have initial values, meaning that a
user need not specify a value in the ctl file if the default value is
acceptable.  If you want to force the user to explicitly give a value
to a variable, set the initial value to <code>'no-value</code>.  (This
way, if the variable is not set by the user, it will fail the
type-constraint and an error will be flagged.)  Such behavior is
deprecated, however.

<h2>Defining output variables</h2>

Output variables, which are passed from the simulation to the ctl
script, are defined in a manner similar to input variables:

<pre>
(define-output-var <i>name type</i>)
</pre>

<p>Notice that output variables have no initial value and no
constraints.  Your C program is responsible for assigning the output
variables when it is called (as is discussed below).

<p>A variable can be both an input variable and an output variable at
the same time.  Such input-output variables are defined with the same
parameters as an input variable:

<pre>
(define-input-output-var <i>name value type [constraints]</i>)
</pre>

<h2>Defining classes</h2>

To define a class, one has to supply the parent class and the properties:

<pre>
(define-class <i>name parent [ properties... ]</i>)
</pre>

<p><code><i>name</i></code> is the name of the new class and
<code><i>parent</i></code> is the name of the parent class, or
<code>no-parent</code> if there is none.

<p>The <code><i>properties</i></code> of the class are zero or more of
the following definitions, which give the name, type, default value,
and (optional) constraints for a property:

<pre>
(define-property <i>name default-value type [ constraints... ]</i>)
</pre>

<p><code><i>name</i></code> is the name of the property.  It is okay
for different classes to have properties with the same name (for
example, both a sphere and a cylinder class might have
<code>radius</code> properties)--however, it is important that
properties with the same name have the same type.  The
<code><i>type</i></code> and optional <code><i>constraints</i></code>
are the same as for <code>define-input-var</code>, described earlier.

<p>If <code><i>default-value</i></code> is <code>no-default</code>,
then the property has no default value and users are required to
specify it.  To give a property a default value,
<code><i>default-value</i></code> should simply be that default value.

<p>For example, this is how we might define classes for materials and
dielectric objects in an electromagnetic simulation:

<pre>
(define-class material-type no-parent
  (define-property epsilon no-default 'number positive?)
  (define-property conductivity 0.0 'number))

(define-class geometric-object no-parent
  (define-property material no-default 'material-type)
  (define-property center no-default 'vector3))

(define-class cylinder geometric-object
  (define-property axis (vector3 0 0 1) 'vector3)
  (define-property radius no-default 'number positive?)
  (define-property height no-default 'number positive?))

(define-class sphere geometric-object
  (define-property radius no-default 'number positive?))
</pre>

<h3>Derived properties</h3>

Sometimes, it is convenient to store other properties with an object
that are not input by the user, but which instead are computed based
on the other user inputs.  A mechanism is provided for this called
"derived" properties, which are created by:

<pre>
(define-derived-property <i>name type derive-func</i>)
</pre>

<p>Here, <code><i>derive-func</i></code> is a function that takes an
object of the class the property is in, and returns the value of the
property.  (See below for an example.) derive-func is called after all
of the non-derived properties of the object have been assigned their
values.

<h3>Post-processed properties</h3>

It is often useful to store a function of the user input into a
property, instead of just storing the input itself.  (For example, you
might want to scale an input vector so that it is stored as a unit
vector.)  The syntax for defining such a property is the same as
<code>define-property</code> except that it has one extra argument:

<pre>
(define-post-processed-property <i>name default-value type
                                process-func [ constraints... ]</i>)
</pre>

<p><code><i>process-func</i></code> is a function that takes one
argument and returns a value, both of the same type as the property.
Any user-specified value for the property is passed to
<code><i>process-func</i></code>, and the result is assigned to the
property.

<p>Here is an example that defines a new type of geometric object, a
<code>block</code>.  Blocks have a <code>size</code> property that
specifies their dimensions along three unit vectors, which are
post-processed properties (with default values of the coordinate
axes).  When computing whether a point falls within a block, it is
necessary to know the projection matrix, which is the inverse of the
matrix whose columns are the basis vectors.  We make this projection
matrix a derived property, computed via the libctl-provided matrix
routines, freeing us from the necessity of constantly recomputing it.

<pre>
(define-class block geometric-object
  (define-property size no-default 'vector3)

  ; the basis vectors, which are forced to be unit-vectors
  ; by the unit-vector3 post-processing function:
  (define-post-processed-property e1 (vector3 1 0 0) 'vector3 unit-vector3)
  (define-post-processed-property e2 (vector3 0 1 0) 'vector3 unit-vector3)
  (define-post-processed-property e3 (vector3 0 0 1) 'vector3 unit-vector3)

  ; the projection matrix, which is computed from the basis vectors
  (define-derived-property projection-matrix 'matrix3x3
    (lambda (object)
      (matrix3x3-inverse
       (matrix3x3
        (object-property-value object 'e1)
        (object-property-value object 'e2)
        (object-property-value object 'e3))))))
</pre>

<h2>Exporting your subroutines</h2>

In order for the ctl script to do anything, one of your C routines
will eventually have to be called.

<p>To export a C routine, you write the C routine as you would
normally, using the data types defined in ctl.h and ctl-io.h (see
below) for parameters and return value.  All parameters must be passed
by value (with the exception of strings, which are of type <code>char
*</code>).

<p>Then, in your specifications file, you must add a declaration of the following form:

<pre>
(define-external-function <i>name read-inputs? write-outputs?
                          return-type
			  [ arg0-type arg1-type ... ]</i>)
</pre>

<p><code><i>name</i></code> is the name of the function, and is the
name by which it will be called in a ctl script.  This should be
identical to the name of the C subroutine, with the exception that
underscores are turned into hyphens (this is not required, but is the
convention we adopt everywhere else).

<p>If <code><i>read-inputs?</i></code> is <code>true</code>, then the
input variables will be automatically imported into C global variables
before the subroutine is called each time.  If you don't want this to
happen, this argument should be <code>false</code>.  Similarly,
<code><i>write-outputs?</i></code> says whether or not the output
variables will be automaticaly exported from the C globals after the
subroutine is called.  All of this code, including the declarations of
the C input/output globals, is generated automatically (see below).
So, when your function is called, the input variables will already
contain all of their values, and you need only assign/allocate data to
the output variables to send data back to Guile.  If
<code><i>write-outputs?</i></code> is <code>true</code>, the output
variables <b>must</b> have valid contents when your routine exits.

<p><code><i>return-type</i></code> is the return type of the
subroutine, or <code>no-return-value</code> if there is no return
value (i.e. the function is of type <code>void</code>).  The remaining
arguments are the types of the parameters of the C subroutine.

<p>Usually, your program will export a <code>run</code> subroutine
that performs the simulation given the input variables, and returns
data to the ctl script through the output variables.  Such a
subroutine would be declared in C as:

<pre>
void run(void);
</pre>

<p>and in the specifications file by:

<pre>
(define-external-function run true true no-return-value)
</pre>

<p>As another example, imagine a subroutine that takes a geometric
object and returns the fraction of electromagnetic energy in the
object.  It does not use the input/output global variables, and would
be declared in C and in the specifications file by:

<pre>
/* C declaration: */
number energy_in_object(geometric_object obj);

; Specifications file:
(define-external-function energy-in-object false false
                          'number 'geometric-object)
</pre>

<h3>Data structures and types</h3>

The data structures for holding classes and other variable types are
defined automatically in the generated file <code>ctl-io.h</code> (see
below).  They are fairly self-explanatory, but it should be noted that
they use some data types defined in <code>src/ctl.h</code>, mostly
mirrors of the corresponding Scheme types.  (e.g. <code>number</code>
is a synonym for <code>double</code>, and <code>vector3</code> is a
structure with <code>x</code>, <code>y</code>, and <code>z</code>
fields.)  (<code>ctl.h</code> also declares several functions for
manipulating vectors and matrices, e.g. <code>vector3_plus</code>.)

<h3>Allocating and deallocating data</h3>

The input variables are allocated and deallocated automatically, as
necessary, but you are responsible for allocating and deallocating the
output data.  As a convenience, the function
<code>destroy_output_vars()</code> is defined, which deallocates all
of the output data pointed to by the output variables.  You are
responsible for calling this when you want to deallocate the output.

<p>Often, after each run, you will simply want to (re)allocate and
assign the output variables.  To avoid memory leaks, however, you
should first deallocate the old output variables on runs after the
first.  To do this, use the following code:

<pre>
if (num_write_output_vars > 0)
     destroy_output_vars();

/* ... allocate & assign the output variables ... */
</pre>

<p>The global variable <code>num_write_output_vars</code> is
automatically set to the number of times the output variables have
been written.

<p>Remember, you are <b>required</b> to assign all of the output
variables to legal values, or the resulting behavior will be
undefined.

<h2>Other useful things to put in a specifications file</h2>

The specifications file is loaded before any user ctl file, making it
a good place to put definitions of variables and functions that will
be useful for your users.  For example, the electromagnetic simulation
might define a default material, <code>air</code>:

<pre>
(define air (make material-type (epsilon 1.0)))
</pre>

<p>You can also define functions (or do anything else that Scheme
allows), e.g. a function to duplicate geometric objects on a grid.
(See the <code>examples/</code> directory of libctl for an example of
this.)

<h2>Writing your program</h2>

Once the specifications have been written, you have to do very little
to support them in your program.

<p>First, you need to generate C code to import/export the
input/output variables from/to Guile.  This is done automatically by
the <code>gen-ctl-io</code> script in the <code>utils/</code>
directory (installed into a <code>bin</code> directory by <code>make
install</code>):

<pre>
gen-ctl-io --code <i>specifications-file</i>
gen-ctl-io --header <i>specifications-file</i>
</pre>

<p>The <code>gen-ctl-io</code> commands above generate two files,
<code>ctl-io.h</code> and <code>ctl-io.c</code>.  The former defines
global variables and data structures for the input/output variables
and classes, and the latter contains code to exchange this data with
Guile.

<p>Second, you should use the <code>main.c</code> file from the
<code>base/</code> directory; if you use the example
<code>Makefile</code> (see below), this is done automatically for you.
This file defines a main program that starts up Guile, declares the
routines that you are exporting, and loads control files from the
command line.  You should not need to modify this file, but you should
define preprocessor symbols telling it where libctl and your
specification file are (again, this is done for you automatically by
the example <code>Makefile</code>).

<p>For maximum convenience, if you are wisely using GNU autoconf, you
should also copy the <code>Makefile.in</code> from
<code>examples/</code>; you can use the <code>Makefile</code>
otherwise.  At the top of this file, there are places to specify your
object files, specification file, and other information.  The
<code>Makefile</code> will then generate the <code>ctl-io</code> files
and do everything else needed to compile your program.

<p>You then merely need to write the functions that you are exporting
(see above for how to export functions).  This will usually include,
at least, a <code>run</code> function (see above).

<p>The default <code>main.c</code> handles a couple of additional
command-line options, including <code>--verbose</code> (or
<code>-v</code>), which sets a global variable <code>verbose</code> to
<code>1</code> (it is otherwise <code>0</code>).  You can access this
variable (it is intended to enable verbose output in programs) by
declaring the global "<code>extern int verbose;</code>" in your
program.

<p>Have fun!

<hr>
Go to the <a href="guile-links.html">next</a>, <a
href="user-ref.html">previous</a>, or <a href="index.html">main</a>
section.


</BODY>
</HTML>