build: fix travis MPI/SMP build
[charm.git] / doc / f90charm / manual.rst
1 ==============================
2 Fortran90 Bindings for Charm++
3 ==============================
4
5 .. contents::
6    :depth: 3
7
8 Charm++ is a parallel object language based on C++. The f90charm module
9 is to provide Fortran90 programs a f90 interface to Charm++. Using the
10 F90Charm interface, users can write Fortran90 programs in a fashion
11 similar to Charm++, which allows creation of parallel object arrays
12 (Chare Arrays) and sending messages between them.
13
14 To interface Fortran90 to Charm++ and thus obtain a parallel version of
15 your program you need to do the following things:
16
17 #. Write a Charm Interface file (extension .ci)
18
19 #. Write your F90 program with f90charmmain() as main program;
20
21 #. Write implementations of Chare entry methods in the F90 program;
22
23 #. Compile and Link with Charm’s Fortran library
24
25 #. Run it!
26
27 Overview
28 ========
29
30 Here we suppose you already know most concepts in Charm++ and have
31 done some Charm++ programming.
32 Unlike in C++, we don’t have classes in Fortran90. Thus, a Chare in
33 F90Charm is represented as a Fortran type structure. Here is an
34 example:
35
36 .. code-block:: fortran
37
38    ! ## Just replace Hello throughout with your chare's name. ##
39    ! ## and add your chare's personal data below where indicated ##
40    ! ## Everything else remains the same ##
41    MODULE HelloMod
42
43    TYPE Hello
44    ! ## your chare's data goes here, the integer below is an example ##
45    integer data
46    END TYPE
47
48    TYPE HelloPtr
49    TYPE (Hello), POINTER :: obj
50    integer*8 aid
51    END TYPE
52
53    END MODULE
54
55 You can think of this module as a Chare declaration. Type [Hello]
56 defines arbitrary user program data and HelloPtr defines the Chare
57 pointer which the Fortran program will use later to communicate with the
58 F90Charm runtime library. The [aid] is the handle of the array returned
59 by the F90Charm library, and the user shouldn’t change it.
60
61 In F90Charm as in Charm++, you need to write a .ci interface file so
62 that the Charm translator will generate helper functions. The syntax of
63 .ci files is the same as in Charm++, however, for F90Charm, there are
64 certain constraints. First, you don’t need to declare the main chare as
65 in Charm++. Second, F90Charm currently only supports up to 3D Chare
66 arrays, and you cannot define Chare, Group, and NodeGroup types. Third,
67 there are no message declarations in .ci files, all the entry functions
68 must be declared in the parameter marshalling fashion of Charm++.
69 Essentially, users can declare in .ci files readonly variables and 1-3D
70 chare arrays with parameter marshalled entry methods.
71
72 It is the programmer’s responsibility to write the implementation of
73 Chare entry methods. The decl and def files generated by Charm++’s
74 translator define the interface functions programmer need to write.
75
76 For each Chare defined in the .ci file, the user must write these
77 functions for F90Charm’s runtime:
78
79 ``SUBROUTINE <ChareName>_allocate(objPtr, aid, index)``
80
81 You can think of this function as a constructor for each array element
82 with array index [index]. For a 3D array, for example, you can replace
83 index in the example by a 3D array index [index1, index2, index3]. In
84 this function the user must allocate memory for the Chare’s user data
85 and perform any initialization.
86
87 For each Chare entry method you have declared, you should write the
88 corresponding Fortran90 subroutine for it:
89
90 ``SUBROUTINE <ChareName>_Entry_<EntryName>(charePtr, myIndex, data1, data2 ... )``
91
92 Note that the first argument is the Chare pointer as declared
93 previously, and the second argument is the array index which will be passed
94 from the Charm runtime. The rest of the parameters should be the same as
95 declared in the .ci file. For higher dimensional
96 arrays, replace ``myIndex`` by ``myIndex1, myIndex2`` for example.
97
98 On the caller side, the decl/def files generated by Charm++’s translator
99 also provide the following functions for Chare creation and remote method
100 invocation. For each Chare declared in .ci files, these subroutines are
101 generated for use in Fortran90 code:
102
103 ``<ChareName>_CkNew(integer n, integer*8 aid)``
104
105 This subroutine creates a chare array of size ``n``. For higher
106 dimensional array creation, specify one integer for each dimension. For
107 example, to create a 3D array:
108
109 ``<ChareName>_CkNew(integer dim1, integer dim2, integer dim3, integer*8 aid)``
110
111 For each entry method, a corresponding ``Invoke`` method is provided (1D
112 example shown here):
113
114 ``<ChareName>_Invoke_<EntryName>(charePtr, myIndex, data1, data2 ... )``
115
116 This subroutine will send a message to the array element with index
117 ``myIndex``. Similarly, for arrays with higher dimensions, replace ``myIndex``
118 by a corresponding number of array indices. Broadcasts are supported as
119 well:
120
121 ``<ChareName>_Broadcast_<EntryName>(charePtr, data1, data2 ... )``
122
123 There are several others things you need to know.
124
125 First, as in Charm++, each .ci file will generate two header files:
126 .decl.h and .def.h. However, in Fortran90 charm, you are not able to
127 include these C++ files in Fortran90 code. Thus, currently, it is the user’s
128 task to write a short C++ file including these two headers files. You
129 should also provide definitions for readonly variables in this C++ file.
130 It can be as simple as this:
131
132 .. code-block:: c++
133
134    #include "hello.decl.h"
135    int chunkSize;  // define readonly variables here
136    #include "hello.def.h"
137
138 In the future, this file could be generated automatically by the
139 translator.
140
141 Second, you can still use readonly variables as in Charm++. However,
142 since there are no global variables as in C++ in Fortran90, you have to
143 access them explicitly via function call. Here are the two helper
144 functions that the translator generates:
145
146 Take the readonly variable chunkSize as an example:
147
148 .. code-block:: c++
149
150    Set_Chunksize(chunkSize);
151    Get_Chunksize(chunkSize);
152
153 These two functions can be used in user’s Fortran program to set and get
154 readonly variables.
155
156 Third, for the user’s convenience, several Charm++ runtime library functions
157 have their Fortran interface defined in the F90Charm library. These
158 currently include:
159
160 .. code-block:: c++
161
162    CkExit()
163    CkMyPe(integer mype)
164    CkNumPes(integer pes)
165    CkPrintf(...)    // note, the format string must terminated with '$$'
166
167 Here is a summary of current constraints to write F90 binding Charm++
168 programs:
169
170 #. Only one- to three-dimensional chare arrays are supported.
171
172 #. readonly variables must be basic types, i.e. they have to be integers,
173    floats, etc. scalar types or array types of these basic scalar types.
174
175 #. Instead of ``program main``, your f90 main program starts from
176    ``subroutine f90charmmain``.
177
178 These details are best illustrated with an example: a hello world program.
179 When executed, an array of several parallel chares is created, forming a ring.
180 Each chare prints a string when it receives a message, and then sends a
181 message to the next chare in the ring. The Fortran ``f90charmmain`` subroutine
182 begins execution, and the ``SayHi`` subroutine performs each chare's task.
183
184 Writing the Charm++ Interface File
185 ==================================
186
187 In this step, you need to write a Charm++ interface file (.ci).
188 In the file you can declare parallel chare arrays and their
189 entry methods. The syntax is the same as in Charm++.
190
191 .. code-block:: c++
192
193          // ## Just replace Hello throughout with your chare's name. ##
194          // ## and add your chare's entry points below where indicated ##
195          // ## Everything else remains the same ##
196          mainmodule hello {
197            // declare readonly variables which once set is available to all
198            // Chares across processors.
199            readonly int chunkSize;
200
201            array [1D] Hello {
202              entry Hello();
203
204              // Note how your Fortran function takes the above defined
205              // message instead of a list of parameters.
206              entry void SayHi(int a, double b, int n, int arr[n]);
207
208              // Other entry points go here
209              entry [reductiontarget] void MyReduction(int result);
210            };
211          };
212
213 Note, you cannot declare a main chare in the interface file, and you
214 also are not supposed to declare messages. Furthermore, the entry
215 functions must be declared with explicit parameters instead of using
216 messages.
217
218 Writing the F90 Program
219 =======================
220
221 To start, you need to create a Fortran Module to represent a chare, e.g.
222 {ChareName}Mod.
223
224 .. code-block:: fortran
225
226          ! ## Just replace Hello throughout with your chare's name. ##
227          ! ## and add your chare's personal data below where indicated ##
228          ! ## Everything else remains the same ##
229          MODULE HelloMod
230
231          TYPE Hello
232          ! ## your chare's data goes here ##
233          integer data
234          END TYPE
235
236          TYPE HelloPtr
237          TYPE (Hello), POINTER ::  obj
238          integer*8 aid
239          END TYPE
240
241          END MODULE
242
243 In the Fortran file you must write an allocate function for this chare
244 with the name: Hello_allocate.
245
246 .. code-block:: fortran
247
248          ! ## Just replace Hello throughout with your chare's name. ##
249          ! ## Everything else remains the same ##
250          SUBROUTINE Hello_allocate(objPtr, aid, index)
251          USE HelloMod
252          TYPE(HelloPtr) objPtr
253          integer*8 aid
254          integer index
255
256          allocate(objPtr%obj)
257          objPtr%aid = aid;
258          ! ## you can initialize the Chare user data here
259          objPtr%obj%data = index
260          END SUBROUTINE
261
262 Now that you have the chare and the chare constructor function, you can
263 start to write entry functions as declared in the .ci files.
264
265 .. code-block:: fortran
266
267          ! ## p1, p2, etc represent user parameters
268          ! ## the "objPtr, myIndex" stuff is required in every Entry Point.
269          ! ## CkExit() must be called by the chare to terminate.
270          SUBROUTINE Hello_Entry_SayHi(objPtr, myIndex, data, data2, len, s)
271          USE HelloMod
272          IMPLICIT NONE
273
274          TYPE(HelloPtr) objPtr
275          integer myIndex
276          integer data
277          double precision data2
278          integer len
279          integer s(len)
280
281          objPtr%obj%data = 20
282          if (myIndex < 4) then
283              call Hello_Invoke_SayHi(objPtr%aid, myIndex+1, 1, data2, len, s);
284          else
285              call CkExit()
286          endif
287
288 Preliminary support for reductions is available as well. Support is
289 limited to reducing from a chare array to the first member of the same
290 array. Only basic built-in reducers are available. For an entry method
291 named MyReduction, tagged as a reduction target in the interface file, a
292 contribution can be made as follows:
293
294 .. code-block:: fortran
295
296          external Hello_ReductionTarget_MyReduction
297
298          call Hello_contribute(objPtr%aid, myIndex, sizeof(myIndex), myValue, CHARM_SUM_INT, Hello_ReductionTarget_MyReduction)
299
300 Now, you can write the main program to create the chare array and start
301 the program by sending the first message.
302
303 .. code-block:: fortran
304
305          SUBROUTINE f90charmmain()
306          USE HelloMod
307          integer i
308          double precision d
309          integer*8 aid
310          integer  s(8)
311
312          call Hello_CkNew(5, aid)
313
314          call set_ChunkSize(10);
315
316          do i=1,8
317              s(i) = i;
318          enddo
319          d = 2.50
320          call Hello_Invoke_SayHi(aid, 0, 1, d, 4, s(3:6));
321
322          END
323
324 This main program creates an chare array Hello of size 5 and send a
325 message with an integer, an double and array of integers to the array
326 element of index 0.
327
328 Compilation and Linking
329 =======================
330
331 Lastly, you need to compile and link the Fortran program with the Charm
332 runtime system as follows: (Let’s say you have written ``hellof.f90``, ``hello.ci`` and
333 ``hello.C``.)
334
335 .. code-block:: bash
336
337    $ charmc hello.ci -language f90charm
338
339 will create ``hello.decl.h`` and ``hello.def.h``.
340
341 .. code-block:: bash
342
343    $ charmc -c hello.C
344
345 will compile ``hello.C`` with ``hello.decl.h`` and ``hello.def.h``.
346
347 .. code-block:: bash
348
349    $ charmc -c hellof.f90
350
351 charmc will invoke the Fortran compiler:
352
353 .. code-block:: bash
354
355    $ charmc -o hello hello.o hellof.o -language f90charm
356
357 will link ``hellof.o`` and ``hello.o`` against Charm’s Fortran90 library to create
358 a new executable program, ``hello``.
359
360 A 2D array example can be found in ``charm/examples/charm++/f90charm/hello2D``.
361
362 Running the Program
363 ===================
364
365 To run the program, type:
366
367 .. code-block:: bash
368
369    $ ./charmrun +p2 hello
370
371 which will run ``hello`` on two PEs.