Level 0 MESA++
This page describes Level 0 MESA++, the foundation for all our
MESA++ development.
What is Level 0 MESA++?
Some wrinkles
Our automatic tools
What is Level 0 MESA++?
Level 0 MESA++ is the foundation on which all of MESA++ is built. It is a comprehensive set of bindings in C++ to the public procedures and variables provided by MESA. We generate these bindings automatically from the MESA code itself every time a new release of MESA is made. Here's how it works.
We compile MESA using a patched version of gfortran that generates a
*.mod.hh C++ header file for every Fortran module it sees, and a *.f.hh
C++ header file for every *.f Fortran file containing global
procedures. For a Fortran procedure or variable named my_symbol in a module named my_module, there will be a C++
declaration in my_module.mod.hh
with the name MOD_SYMBOL_NAME(my_symbol,
my_module)decorated with the correct C++ translation of the type
of the symbol. The issues involved in translating the type are
discussed
here.
These declarations are a bit awkward to use because of the
SYMBOL_NAME and MOD_SYMBOL_NAME macros required to turn a Fortran
symbol name into a C++ symbol name. To make things easier, we bind a
C++ reference to each such symbol that allows it to be accessed by its
original short Fortran name. To avoid any possibility of name
collisions between symbols with identical names in different FORTRAN
modules, we put the C++ bindings in namespaces whose names reflect the
names of the original Fortran modules.
Thus, the file mesapp/alert/private/alert_lib.mod.hh
contains the declaration
which matches the declaration of the alert_info variable in the MESA alert_lib module. the MOD_SYMBOL_NAME macro provides a portable way for us to convert the Fortran name into the corresponding C++ name on different platforms. Since the macro is a bit awkward, this declaration is followed by a second declaration:
{
EXTERN int (&alert_info) MOD_REFERENCE(alert_info, alert_lib);
}
This creates a separate C++ reference to alert_info
in the namespace Mesa_alert_lib_L0
that does not require a macro. You can then use either a using Mesa_alert_lib_L0::alert_info
statement or a using
namespace Mesa_alert_lib_L0 statement to make it possible to
access this variable.
We don't actually expect you to directly #include any *.mod.hh or *.f.hh files in your code, which is why we put them in the private directories. Nor do we expect you to routinely use names from the various Mesa_module_L0 namespaces, though that option is always open to you. Instead, we anticipate that most programmers will routinely #include the corresponding public/module.hh headers and use the Mesa_module namespaces instead. We incorporate many of the Mesa_module_L0 symbols into the Mesa_module namespace, and replace others with somewhat more C++-friendly substitutes. The original Mesa_module_L0 declarations are always available when you #include the public/module.hh header, if you do need direct access to them.
Some wrinkles
We can handle almost all variables and procedures from MESA in this
manner. However, procedures taking variable-length character arguments
are an exception, because there is no portable way to translate their
declarations into C++. We handle these by introducing an extra layer of
Fortran wrappers in which the variable length character arguments are
replaced by explicit length character arguments.
If you look in the mesapp/alert/private directory, you will see two
files, alert_lib_flat.f
and alert_lib_flat.mod.hh,
that
illustrate
this
wrapping.
The
MESA
alert_lib
module contains subroutines, such as alert, that
take variable length character arguments. The file alert_lib_flat.f
wraps alert
in a new function, alert_flat,
that replaces the variable length character argument with a
explicit-length character argument whose length is specified by a
second integer argument. The alert_lib_flat.mod.hh header then provides
the corresponding C++ declaration, which is included in public/alert_lib.hh
and there brought into the Mesa_alert_lib
namespace.
Another special case is integer and floating point constants, declared PARAMETER in MESA modules. These do not actually appear in object files (unless they are arrays, which we can treat much like other Fortran variables.) Thus we cannot bind a reference to them as we do other Fortran symbols. Fortunately, we don't need to: Our automatic tools simply declare these constants as C++ constants with the appropriate values in the Mesa_module_L0 namespaces. They can then be used wherever a constant expression is needed in C++ code, including specifying dimensions in array declarations.
Some other declarations are translatable, but a touch awkward to deal with. We don't attempt to deal with that awkwardness in Level 0 MESA++, but will address it it in higher levels of MESA++. However, you should be aware of the issues.
One bit of awkwardness is the various kinds of arrays that can be
passed into Fortran procedures. If the array shape of the dummy
argument is explicit, the array is passed as a C++ array and poses no
particular problem, except that all explicit arrays are treated as
one-dimensional arrays on the C++ side regardless of their dimension on
the Fortran side. (This is discussed here.)
However,
if
a
Fortran
procedure
has
a deferred array dummy argument,
then the procedure expects shape information to be passed into the
array along with the array pointer. We can handle this portably, if
slightly awkwardly, by defining a Shape<type,
rank> struct template whose exact definition depend on the
platform. You just need to install the right generate-hh.hh for you
platform from those in mesapp/cxx/skel.
Regardless
of
platform,
Shape
will
include a member, data, that
points at the actual array data, and you can access the element you
want using a computed index. The sizing information can be portably
read using the size
functions we've provided in the mesapp/utils package.
A Shape
is always initialized by a call to some Fortran procedure. Many MESA
functions initialize one or more of the Shape
arguments in their argument list, in which case you don't need to. When
you do need to initialize a Shape yourself, you can use some of the
functions in the mesapp/utils
library. The allocate
functions perform allocation from scratch, while the flat_to_shape
functions wrap an existing C++ array into a Shape with
the approriate size information. You can also explicitly deallocate a
Shape using the deallocate
functions. If you want to use the standard vector
template class on the C++ side of your code (and why not?) you will
sometimes need to use the data()
member function to get a pointer to the raw storage so you can pass it
to a Fortran function, or so you can wrap it in a Shape that will be
passed to a Fortran function.
If you are calling a Fortran procedure that initializes a Shape
argument, you are pretty much stuck having to use the Shape
directly, or else pay the cost to copy the data into your vector. We
will doubtless have to wrestle with this issue some more as we develop
the higher levels of MESA++.
Our automatic tools
You do not need our patched version of gfortran to use MESA++! You do not even need to use gfortran; we intend to support ifort/icpc as well. We generate the *.mod.hh and *.f.hh files automatically every time there is a new release of MESA, and we put them in the Subversion repository for your use. However, if you modify MESA locally, you may need to modify the corresponding MESA++ *.mod.hh or *.f.hh files by hand. This is fairly straightforward once you understand how the interface works. This document is here to help you do that.
And, yes, we mean to make our patch to gfortran publicly available
in the near future, on a separate Sourceforge site. Stay tuned.
website
design
by
Andreas Viklund