doxygen.lib.txt 18 KB
Newer Older
1
/*! \file libaff/lib/doxygen.lib.txt
2
3
4
5
 * \brief Some more specific or more advanced topics
 *
 * ----------------------------------------------------------------------------
 *
6
 * $Id$
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
 * 
 * Copyright (c) 2002 by Thomas Forbriger (IMG Frankfurt) 
 *
 * ----
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 * ----
 * 
 * Some more specific or more advanced topics
 *
 * This file contains documentation for
 *  - namespace aff::util
 *  - \ref page_representation
 *  - \ref page_fortran
 * 
 * REVISIONS and CHANGES 
 *  - 08/12/2002   V1.0   copied from libcontxx
 *  - 20/12/2002   V1.1   (thof)
 *                        - complete revision of this file
 *  - 27/12/2002   V1.2   (thof)
 *                        - completed Fortran considerations
 *                        - doxygen now reads Fortran and f2c generated code
 *  - 28/12/2002   V1.3   (thof)
 *                        - new term for containers of const elements
42
43
 *  - 12/06/2013   V1.4   (thof)
 *                        - renamed file
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
 * 
 * ============================================================================
 */

namespace aff {

/*! \brief Internal utilities
 *
 * In this namespace we collect modules that need not necessarily be exposed
 * to the user.
 */
namespace util {
} // util
} // aff

/*======================================================================*/

/*! \page page_representation The concept of represented memory

  Contents of this page:
  - \ref sec_representation_sharedheap
  - \ref sec_representation_introduction

\section sec_representation_introduction Introduction

The array and iterator classes in this library should be insulated from the
representation of the handled data in memory. 
Also they should be able to share references to the same memory area.
Since returning an array from a function automatically invokes the copy
constructor, this representation should have reference semantics.
Using the same representation class (here aff::SharedHeap) as a basis for all
containers (like aff::Array and aff::Series) and iterators, we may easily
convert an aff::Series into an aff::Array without copying the data. Both
objects just provide a different access interface to the data in memory.

To use memory representations with reference semantics has some implications
for the definition of the assignment operator. We have to decide between a
deep copy (elementwise copy) and a shallow copy (copying the representation).

\sa \ref sec_design_copy


\section sec_representation_sharedheap Shared heap

  This type of memory access 
  implements array handle semantics. On creation this
  class allocates memory on the free store (heap) to be used for the array
  elements. On a copy only a reference to the free store location is copied.
  Thus always a shallow copy is performed. The represenation itself takes care
  about the number of instances referencing the free store location. On
  destruction of the last of these instances, the free store location is
  freed.

  Additionally aff::SharedHeap offers a facility to take a global memory
  pointer on creation. In this case, memory management lies outside the
  representation class and the underlying aff::SHeap object will \em never
  call the delete operator in the destructor. This is usefull when interfacing
  arrays allocated through Fortran code subroutines.

  Creating an array projection may be
  done by copying the representation (reference to free store) with an array
  instance that only accesses a subset of the elements in the heap location.
  Thus projections may be created as true arrays (you don't have do
  distinguish between projections and true arrays in your code - like the
  sliced arrays in the STL must). However,
  changes applied to the array elements through the projection imediately
  affects the full array, in fact data of all array copies are affected by 
  "write"-operations to the instances.

  This way of memory access allows easy and cheap copying of arrays. We may
  pass them freely to functions or receive them as return values. It doesn't
  matter where the array is actually created. Itself takes care about memory
  allocation. And it always does a shallow copy, with almost no overhead to
  passing a reference.

  By this mechanism, we may hold different projections to the same data, which
  are all full qualified arrays (even with possibly different dimensionality).
  For example, we may hold a complete set of earth model parameters.
  We may like to
  address them either in the sense of inversion parameters as a full set or in
  the sense of there physical meaning. In the latter case we may like to
  address the p-velocities as a subset. However, when any of the (anonymous)
  inversion parameters are changed, the change should immediatly be reflected
  by the projection that represents the physical parameters and vice versa.

  The same memory data may even be shared by objects of different class types.
  In this way an aff::Array may interface the same data in memory as a
  simultaneous aff::Series object.

  This is implemented by class aff::SharedHeap.
  It is presented in aff/lib/sharedheap.h

  \sa \ref sec_design_const

*/

/*======================================================================*/

/*! \page page_fortran Interfacing Fortran 77

  Contents of this page:
  - \ref sec_fortran_general
  - \ref sec_fortran_call
  - \ref sec_fortran_common
  - \ref sec_fortran_links
  - \ref sec_fortran_source
  - \ref sec_fortran_f2c

  After switching to C++ many numerical routines coded in Fortran 77 will stay
  in use. Recoding them in C++ should not generally be considered. It involves
  a lot of extra work and potentially introduces new bugs and errors to code
  that was well tested before. Thus some of our C++ functions have to call
  underlying Fortran 77 code and must exchange data with this code, in
  particular. Exchanging data also involves passing arrays to and from
  Fortran. 

  The example tests/f77test.cc and its associates demonstrates how AFF data
  may be passed to Fortran and how Fortran arrays may be integrated into AFF.

  \sa namespace f77interface
  \sa tests/f77interface.cc
  \sa tests/f77proto.h
  \sa \ref sec_fortran_f77procsf
  \sa \ref sec_fortran_f77commoninc
  \sa tests/Makefile
 

\section sec_fortran_general Some general considerations

\par Compiler
  There are two common Fortran 77 compilers available on Linux platforms:
  The GNU Fortran 77 (g77) from the GNU compiler collection
       ("http://www.gnu.org/software/gcc/gcc.html") and
  the Fortran to C compiler (f2c) published through netlib
       ("http://netlib.bell-labs.com/netlib/f2c/index.html").

\par
  When compiling the C++ part with the g++ from the GNU compiler collection it
  may seem natural to use g77 for the Fortran part. However, when interfacing
  the Fortran components, we have to know about the internals of the compiled
  Fortran code so that the linker will find the components, that we wish to
  access. g77 does not expose these internals, in particular it may operate in
  different modes (f2c compatible or not) and is subject to future changes. 
  f2c on the other hand exposes the intermediate C code, which is then
  compiled by gcc from the GNU compiler collection and may easily be linked to
  C++ code.

\par 
  \b Decision:
  We use f2c and gcc in our examples of interoparting Fortran code and AFF.

\par Prototypes
  Source code is usually separated into different compilation units (source
  files). These code fragmemts must be kept synchronous, i.e. all calls to a
  function must use the same (and correct) formal parameters, all access to
  global data (e.g. common blocks) must use the same declaration.

\par
  While C offers a control mechanism to ensure snychronous code (through
  prototypes and header files), Fortran 77 does not. A common technique with
  Fortran is to read common block definitions from extra files (using the
  include statement), thus ensuring that every function and subroutine uses
  the same definition. How can we ensure that later changes applied to the
  Fortran code will be recognized in the interoperating C++ code?

\par 
  \b Decision:
  We make extensive use of header files and prototypes that can be generated
  with f2c. This makes interface code more complicated (i.e. splits it into
  more different compilation units) and introduces more header files (e.g.
  tests/f77common_com.P and tests/f77procs.P) but introduces more safety too.
 
Aspects to consider:
  -# Passing pointers of Fortran type to pointer of C++ type
     (reinterpret_cast)
  -# Creating function call prototypes
  -# factoring out interfacing issues to seperate compilation unit and
     interface functions
  -# creating function call prototypes with extern "C" linkage
  -# creating common block declarations with extern linkage
  -# passing fixed array dimensions from Fortran to C++
  -# passing variable array dimensions from Fortran common block to C++
  -# how to satisfy linker with a MAIN__ function
  -# compiling f2c output with g++ (using -C++ option)


\section sec_fortran_call Passing arrays through function calls

  An example for passing AFF data to a Fortran function is given in 
  f77interface::fill. The interface function is defined in
  tests/f77interface.cc and presented in tests/f77proto.h. It is declared
  \code
  int f77interface::fill(const aff::Array<int>& a)
  \endcode
  The Array is converted into an aff::FortranArray by
  \code aff::FortranArray<int> fa(a); \endcode
  within the function.
  From this the function retrieves the appropriate Fortran layout of the
  array.

  In case the Fortran code is modfified we only have to keep track within the
  interface module (i.e. tests/f77interface.cc and tests/f77proto.h).

  Aspects that had to be considered:
    - The corresponding Fortran subroutine in tests/f77procs.f is compiled by
      f2c and g++. Hence we pass the -C++ option to f2c.
    - We have to link against libf2c.a and libm.a or their dynamic companions.
    - We have to provide a MAIN__() function in our code to satisfy the
      linker (discovered by wolle). This function, however is never called.
      It must be declared with \c extern \c "C" linkage.
    - For calling the Fortran functionality we provide an extra C++ interface.
      This interface is presented in tests/f77proto.h and namespace
      f77interface. The definitions are coded in tests/f77interface.cc.
    - To ensure synchronous code between Fortran and the C++ interface, we use
      prototypes written by f2c. They are generated by
      \verbatim f2c -C++ -P -\!c tests/f77procs.f \endverbatim
      to file \ref sec_fortran_f77procsp
    - The prototypes are not declared with external C linkage. Therefore the
      correspnding include section in tests/f77interface.cc reads like
      \code extern "C" { #include "f77procs.P" } \endcode
    - Additionally we must include \c f2c.h in tests/f77interface.cc.
    - Within f77interface::fill type conversion must take place. The array
      shape is derived as C++ \c int values. They are converted to values of
      type \c integer (defined in f2c.h) with statements like
      \code integer n1=fa.last(0); \endcode 
      and passed to the Fortran function as pointers of type \c integer* by
      \code fill_(pa, &l1, &n1, &l2, &n2, &l3, &n3) \endcode
    - The array values are access within the Fortran subroutine through a
      pointer to the first element. This pointer is of type \c integer*,
      which is defined as \c long \c int* in f2c.h. From the FortranArray
      object we receive a pointer of type \c int*. The only way I see to
      convert it is via
      \code integer* pa=reinterpret_cast<integer *>(fa.pointer()); \endcode
      which is a totally unchecked conversion. 
      Since the type size is known at compile-time, there should be a more
      elegant way.
      And there is: Have a look at aff::util::SizeCheckedCast. The more recent
      version of tests/f77test.cc uses the aff::FortranArray::castedpointer
      member template function, which again calls a compile-time size-check.
 

\section sec_fortran_common Accessing arrays in common blocks

  In many Fortran code modules essential array data is passed through global
  common blocks between subroutines. It is possible to make this data visible
  in form of an aff::Array object. However, this is slightly more complicated
  than passing a C++ array to an underlying Fortran subroutine.

  An example for this technique is given by the following functions:
    -# f77interface::fillarray takes two 1D aff::Array<float> arguments and
       passes them to the Fotran subroutine fillarray which calculates the
       contents of a complex common block array from them.
    -# f77interface::sums takes the result of the Fortran subroutine sums,
       which calculates column-sums of the common block array, and
       returns them as an aff::Array.
    -# f77interface::viewcommon returns an aff::Array that offers direct
       read/write access to the Fortran common block.
 
  The interface functions are presented in tests/f77proto.h, are defined in
  tests/f77interface.cc and the underlying Fortran subroutines are defined in
  \ref sec_fortran_f77procsf.
  The common-block itself is defined in \ref sec_fortran_f77commoninc.
  f77interface::viewcommon is the module that actually allows direct
  read/write acces to the common block. The other two provide means to access
  the same common block from tests/f77test.cc through calls to Fortran
  subroutines.

  Addtionally to the considerations for \ref sec_fortran_call we have to
  discuss the following:
    - f77interface::fillarray passes AFF arrays to Fortran code just in the
      way f77interface::fill discussed above. Since Fortran doesn't know of
      const-correctness it takes arguments of type 
      \code const aff::Array<float>& \endcode
      rather than
      \code const aff::ConstArray<float>& \endcode
      (see also \ref sec_design_const).
    - f77interface::sums has to create an AFF array of appropriate size before
      passing a pointer to the underlying Fortran subroutine. Since the
      dimensions of fixed sized Fortran arrays are usually given by parameter
      constants that are defined in include files, these values are not
      accessible from the C++ code. We therefore introduced a Fortran
      subroutine \c comdim, which can be used to read the dimensions of the
      common-block array.
    - f77interface::viewcommon creates an AFF array, which is simply a
      reference to the common-block array and has appropriate shape. Shape and
      representation (i.e. SharedHeap) are craeted separately. The SharedHeap
      is intialized by
      \code aff::SharedHeap<Tzvalue> repr(p, shape.memory_size()); \endcode
      from a pointer \c p and a size in memory. Using this constructor
      ensures, that SharedHeap will never try to deallocate the memory block.
    - The common block definition is not visible from C++. To ensure
      synchronous code after changes being applied to the Fortran code, we
      must make use of automatic code generation by f2c. We use
      \verbatim f2c -C++ -f -u -ec tests/f77procs.f
 sed -e 's/^struct/extern struct/' tests/f77common_com.c > tests/f77common_com.P \endverbatim
      to create a common block definition in \ref sec_fortran_f77commoncomp.
      This definition is read via
      \code #include"f77common_com.P" \endcode
      in tests/f77interface.cc.
      The common block is then available as
      \code extern struct { ... } f77common_ \endcode
      with \c extern \c "C" linkage in the C++ code.
    - \b Notice: The access shape of the AFF array returned by
      f77interface::viewcommon is defined upon creation of the array.
      Changing the actual access shape in the common block later (i.e. the
      common block members \c na and \c nb), e.g. by calling subroutine
      fillarray, is not reflected by the AFF array. This will first be noticed
      by the next call to f77interface::viewcommon. It is the responsibility
      of the programmer to avoid inconsistencies due to different access
      shapes in Fortran and C++.


\section sec_fortran_links Links to other helpful information

  - In the manual of the GNU Fortran 77 compiler you will find a section
    discussing "Interoperating with C and C++".
    - http://gcc.gnu.org/onlinedocs/g77/Interoperating-with-C-and-C--.html#Interoperating%20with%20C%20and%20C++
    - http://gcc.gnu.org/onlinedocs/

  - Burkhard D. Steinmacher-Burow provides cfortran.h for "Interfacing C or C++
    and Fortran".
    - http://www-zeus.desy.de/~burow/cfortran/index.htm
    - http://www-zeus.desy.de/~burow/cfortran/cfortran.html

  - A very usefull tool for coding interfaces to Fortran 77 is the f2c
    compiler. Its documentation provides a lot of useful information about 
    the way Fortran code objects may be accessed from C and C++.
    - http://netlib.bell-labs.com/netlib/f2c/index.html

  - Further discussions may be found at other places:
    - http://wwwinfo.cern.ch/asdcgi/listcernlibfaqs.pl/3
    - http://home.online.no/~arnholm/cppf77.htm
    - http://www.llnl.gov/CASC/components/babel.html


\section sec_fortran_source Fortran 77 Source code

\subsection sec_fortran_f77commoninc tests/f77common.inc
  \verbinclude tests/f77common.inc

\subsection sec_fortran_f77procsf tests/f77procs.f
  \verbinclude tests/f77procs.f

\section sec_fortran_f2c Code generated by f2c

\subsection sec_fortran_f77commoncomp tests/f77common_com.P
  \verbinclude tests/f77common_com.P

\subsection sec_fortran_f77procsp tests/f77procs.P
  \verbinclude tests/f77procs.P
*/
395
// ----- END OF doxygen.lib.txt -----