1 ===================================================
2 Parallel Framework for Unstructured Meshes (ParFUM)
3 ===================================================
30 Program Structure, Compilation and Execution
31 ============================================
33 .. _sec:getting_parfum:
38 ParFUM is built on Charm++ so you must begin by downloading the latest
39 source version of Charm++ from ``http://charm.cs.illinois.edu/``. Build the
40 source by running ``./build`` and answering the interactive prompts, or
41 by manually specifying the configuration you want to the build script.
42 Make sure to build the Charm++ libraries, not just the core system.
44 In a charm installation, see charm/examples/ParFUM/ for example and test
47 Structure of a Typical ParFUM Program
48 -------------------------------------
50 A typical ParFUM program consists of two functions: ``init()`` and
51 ``driver``. The ``init()`` function runs only on the first processor,
52 and typically does specialized I/O and startup tasks. In most ParFUM
53 programs ``init()`` is primarily used to read in a serial mesh. Once
54 ``init()`` completes, ParFUM partitions the mesh and distributes it
55 among all processors. Then ``driver()`` is called for every chunk on
56 every processor and performs the main work of the program. This program
57 structure is shown in Figure :numref:`parfum_structure`. In the
58 language of the TCHARM manual, ``init()`` runs in the serial context and
59 ``driver()`` runs in the parallel context.
61 .. figure:: fig/parfum_structure.png
62 :name: parfum_structure
65 A typical ParFUM program consists of an ``init()`` function running
66 in serial context and a ``driver()`` function running in parallel
69 In pseudocode, a simple ParFUM program would have the following
75 read the serial mesh and configuration data
77 /* after init, the FEM framework partitions the mesh */
82 communicate boundary conditions
87 ParFUM Programs without init/driver
88 -----------------------------------
90 Although ParFUM provides the init/driver structure as a convenience to
91 the programmer, you can write a ParFUM program without using init or
92 driver. This is a more flexible approach, but it is more complicated
93 than an init/driver program.
95 In pseudocode, a ParFUM program with a stand-alone main function might
102 FEM_Init(MPI_COMM_WORLD)
103 if (I am master processor)
108 communicate boundary conditions
109 more FEM computations
113 In this mode, the FEM framework does not set a default reading or
114 writing mesh, and does no partitioning; you must use the FEM_Mesh
115 routines to create and partition your mesh. See the AMPI manual for
116 details on how to declare the main routine, or the file main.C in ParFUM
117 for an example of how to write a stand-alone main routine. Compiling a
118 ParFUM program without init or driver requires slightly different link
119 flags than a typical ParFUM program, see the compilation section for
125 To compile and link a ParFUM program, you must first have a working copy
126 of Charm++ and the ParFUM libraries. The process for downloading and
127 building this software is described in section
128 :numref:`sec:getting_parfum`.
130 To compile a FEM program, compile and link using ``charmc``, and pass
131 the flag ``-language ParFUM`` to charmc when linking. If your program
132 uses its own ``main`` function rather than init and driver, pass
133 ``-language AMPI`` instead.
138 At runtime, a Charm++/FEM framework program accepts the following
139 options, in addition to all the usual Charm++ options described in the
140 Charm++ “Installation and Usage Manual”.
144 Create :math:`v` mesh chunks, or “virtual processors”. By default,
145 the number of mesh chunks is equal to the number of physical
146 processors (set with ``+p`` :math:`p`).
150 Skip driver(). After running init() normally, the framework
151 partitions the mesh, writes the mesh partitions to files, and exits.
152 As usual, the ``+vp`` :math:`v` option controls the number of mesh
155 This option is only used in programs with an ``init`` function.
159 Skip init(). The framework reads the partitioned input mesh from
160 files and calls driver(). Together with ``-write``, this option
161 allows you to separate out the mesh preparation and partitioning
162 phase from the actual parallel solution run.
164 This can be useful, for example, if init() requires more memory to
165 hold the unpartitioned mesh than is available on one processor of the
166 parallel machine. To avoid this limitation, you can run the program
167 with ``-write`` on a machine with a lot of memory to prepare the
168 input files, then copy the files and run with ``-read`` on a machine
169 with a lot of processors.
171 ``-read`` can also be useful during debugging or performance tuning,
172 by skipping the (potentially slow) mesh preparation phase. This
173 option is only used in programs with a ``driver`` function.
175 - ``+tcharm_trace fem``
177 Give a diagnostic printout on every call into the ParFUM framework.
178 This can be useful for locating a sudden crash, or understanding how
179 the program and framework interact. Because printing the diagnostics
180 can slow a program down, use this option with care.
196 Basic Mesh Operations
197 ---------------------
227 Mesh Entity Operations
228 ~~~~~~~~~~~~~~~~~~~~~~
237 Advanced Mesh Entity Operations
238 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
249 Basic Mesh Operations
250 ~~~~~~~~~~~~~~~~~~~~~
259 Advanced Mesh Operations
260 ~~~~~~~~~~~~~~~~~~~~~~~~
264 Mesh Communication: Ghost Layers
265 --------------------------------
274 .. _SectionGhostLayerCreation:
281 Symmetries and Ghosts: Geometric Layer
282 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
286 Advanced Symmetries and Ghosts: Lower Layer
287 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
291 Older Mesh Operations
292 ---------------------
301 .. _ghost-numbering-1:
308 Backward Compatibility
309 ~~~~~~~~~~~~~~~~~~~~~~
323 Topological Mesh Data
324 ---------------------
326 A ParFUM application can request that the ParFUM framework compute
327 topological adjacencies. All ParFUM applications initially specify the
328 mesh as a set of elements, each element defined by a fixed number of
329 nodes. ParFUM can compute and maintain other sets of adjacencies such as
330 which elements are adjacent to a given node, or which nodes are
331 adjacent(they are both associated with a single element), or which
332 elements share an edge/face with another element. Currently only a
333 single element type is supported, and that element must be
334 ``FEM_ELEM+0``. To generate the structures storing the other types of
335 adjacencies, each process in the ParFUM application should call the
336 following subroutines:
339 ``FEM_Add_elem2face_tuples(int mesh, 0, nodesPerFace, numFacesPerElement, faces);``
340 specifies the topology of an element, specifically the configuration of
341 its faces(if 3D) or edges(if 2D). Two elements are adjacent if they
342 share a common face. The parameter faces is an integer array of length
343 :math:`nodesPerFace \cdot numFacesPerElement`. The description is the
344 same as used for determining ghost layers in section
345 :numref:`SectionGhostLayerCreation`.
347 ``FEM_Mesh_allocate_valid_attr(int mesh, int entity_type);``
349 ``FEM_Mesh_create_node_elem_adjacency(int mesh);``
351 ``FEM_Mesh_create_node_node_adjacency(int mesh);``
353 ``FEM_Mesh_create_elem_elem_adjacency(int mesh);``
355 These subroutines can be called in ``init`` on a sequential mesh, or
356 after partitioning in ``driver``. The adjacencies will contain
357 references to ghost elements if the subroutines were called in
358 ``driver`` when ghosts are used. The indexes to ghosts are negative
359 integers which can easily be converted to positive indices by using the
360 function ``FEM_To_ghost_index(id)``. The C header ``ParFUM_internals.h``
361 is required to be included by the ParFUM application to access the
362 adjacencies. The functions to access the adjacencies are in sections
363 :numref:`adjacencies-e2e`, :numref:`adjacencies-n2e`,
364 and :numref:`adjacencies-n2n`.
366 The internal data structures representing the adjacencies are maintained
367 correctly when the adaptivity operations described in section
368 :numref:`Subsection-Mesh-Adaptivity` are used.
372 Accessing Element to Element Adjacencies
373 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
375 ``void e2e_getAll(int e, int *neighbors);`` places all of element e’s
376 adjacent element ids in neighbors; assumes ``neighbors`` is already
377 allocated to correct size
379 ``int e2e_getNbr(int e, short idx);`` returns the id of the idx-th
384 Accessing Node to Element Adjacencies
385 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
387 ``n2e_getLength(int n)`` returns the number of elements adjacent to the
390 ``n2e_getAll(int n, int *&adjelements, int &sz)`` for node ``n`` place
391 all the ids for adjacent elements into ``adjelements``. You can ignore
392 sz if you correctly determine the length beforehand.
396 Accessing Node to Node Adjacencies
397 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
399 ``n2n_getLength(int n)`` returns the number of nodes adjacent to the
402 ``n2n_getAll(int n, int *&adjnodes, int &sz)`` for node ``n`` place all
403 the ids for adjacent nodes into ``adjnodes``. You can ignore sz if you
404 correctly determine the length beforehand.
406 .. _Subsection-Mesh-Adaptivity:
414 If a ParFUM application wants to use parallel mesh adaptivity, the first
415 task is to call the initialization routine from the *driver* function.
416 This creates the node and element adjacency information that is
417 essential for the adaptivity operations. It also initializes all the
418 mesh adaptivity related internal objects in the framework.
420 ``void FEM_ADAPT_Init(int meshID)``
422 Initializes the mesh defined by meshID for the mesh adaptivity
428 For every element entity in the mesh, there is a desired size entry for
429 each element. This entry is called meshSizing. This meshSizing entry
430 contains a metric that determines element quality. The default metric is
431 the average of the length of the three edges of an element. ParFUM
432 provides various mechanisms to set this field. Some of the adaptive
433 operations use these metrics to maintain quality. In addition, there is
434 another metric which is computed for each element and maintained during
435 mesh adaptivity. This metric is the ratio of the longest side to the
436 shortest altitude, and this value is not allowed to go beyond a certain
437 limit in order to maintain element quality.
439 ``void FEM_ADAPT_SetElementSizeField(int meshID, int elem, double size);``
441 For the mesh specified by meshID, for the element elem, we set the
442 desired size for each element to be size.
444 ``void FEM_ADAPT_SetElementSizeField(int meshID, double \*sizes);``
446 For the mesh specified by meshID, for the element elem, we set the
447 desired size for each element from the corresponding entry in the sizes
450 ``void FEM_ADAPT_SetReferenceMesh(int meshID);``
452 For each element int this mesh defined by meshID set its size to the
453 average edge length of the corresponding element.
455 ``void FEM_ADAPT_GradateMesh(int meshID, double smoothness);``
457 Resize mesh elements to avoid jumps in element size. That is, avoid
458 discontinuities in the desired sizes for elements of a mesh by smoothing
459 them out. Algorithm based on h-shock correction, described in Mesh
460 Gradation Control, Borouchaki et al.
465 Once the elements in the mesh have been prepared by specifying their
466 desired sizes, we are ready to use the actual adaptivity operations.
467 Currently we provide Delaunay flip operations, edge bisect operations
468 and edge coarsen operations, all of which are implemented in parallel.
469 We provide several higher level functions which use these basic
470 operations to generate a mesh with higher quality elements while
471 achieving the desired sizing.
473 ``void FEM_ADAPT_Refine(int meshID, int qm, int method, double
474 factor,double \*sizes);``
476 Perform refinements on the mesh specified by meshId. Tries to
477 maintain/improve element quality by refining the mesh as specified by a
478 quality measure qm. If method = 0, refine areas with size larger than
479 factor down to factor If method = 1, refine elements down to sizes
480 specified in the sizes array. In this array each entry corresponds to
481 the corresponding element. Negative entries in sizes array indicate no
484 ``void FEM_ADAPT_Coarsen(int meshID, int qm, int method, double
485 factor,double \*sizes);``
487 Perform refinements on the mesh specified by meshId. Tries to
488 maintain/improve element quality by coarsening the mesh as specified by
489 a quality measure qm. If method = 0, coarsen areas with size smaller
490 than factor down to factor If method = 1, coarsen elements up to sizes
491 specified in the sizes array. In this array each entry corresponds to
492 the corresponding element. Negative entries in sizes array indicate no
495 ``void FEM_ADAPT_AdaptMesh(int meshID, int qm, int method, double
496 factor,double \*sizes);``
498 This function has the same set of arguments as required by the previous
499 two operations, namely refine and coarsen. This function keeps using the
500 above two functions until we have all elements in the mesh with as close
501 to the desired quality. Apart from using the above two operations, it
502 also performs a mesh repair operation which gets rid of some bad quality
503 elements by Delaunay flip or coarsening as the geometry in the area
506 ``int FEM_ADAPT_SimpleRefineMesh(int meshID, double targetA, double xmin,
507 double ymin, double xmax, double ymax);``
509 A region is defined by (xmax, xmin, ymax, ymin) and the target area to
510 be achieved for all elements in this region in the mesh specified by
511 meshID is given by targetA. This function only performs a series of
512 refinements on the elements in this region. If the area is larger, then
513 no coarsening is done.
515 ``int FEM_ADAPT_SimpleCoarsenMesh(int meshID, double targetA, double xmin,
516 double ymin, double xmax, double ymax);``
518 A region is defined by (xmax, xmin, ymax, ymin) and the target area to
519 be achieved for all elements in this region in the mesh specified by
520 meshID is given by targetA. This function only performs a series of
521 coarsenings on the elements in this region. If the area is smaller, then
522 no refinement is done.
524 Verifying correctness
525 ---------------------
527 We provide a checking function that can be used for debugging purposes
528 to identify corrupted meshes or low quality elements.
530 ``void FEM_ADAPT_TestMesh(int meshID);``
532 This provides a series of tests to determine the consistency of the mesh
552 Advanced Index List Calls
553 ~~~~~~~~~~~~~~~~~~~~~~~~~
567 Advanced Layout Routines
568 ~~~~~~~~~~~~~~~~~~~~~~~~
572 Layout Compatibility Routines
573 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
582 Communication Routines
583 ~~~~~~~~~~~~~~~~~~~~~~
587 Advanced Communication Routines
588 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
592 Old Communication Routines
593 --------------------------