Is Fortran a multiple dispatch programming language? - fortran

Does the INTERFACE statement in Fortran make it a programming language officially implementing multiple dispatch? (I ask because the Wikipedia article linked does not feature Fortran among its seemingly comprehensive listing of example programming languages supporting the paradigm in question).

Interface blocks (introduced by the interface keyword) are often used for generic interfaces. They work like C++ generics, no dynamic dispatch. You must distinguish static dispatch and dynamic dispatch. Both Fortran and C++ only have single dynamic dispatch by polymorphism using classes and inheritance/overloading.
But interface blocks themselves have several independent kinds of usage in Fortran and only some deal with some kind of overloading. Often they just work like a function declaration in a C++ header.
Take the example from https://www.geeksforgeeks.org/function-overloading-c/ :
void add(int a, int b)
{
cout << "sum = " << (a + b);
}
void add(double a, double b)
{
cout << endl << "sum = " << (a + b);
}
In Fortran you can do the same but instead declaring both subroutines with the same name straight away, you define two specific subroutines with a different name and make a generic interface for them
interface add
procedure add_ints
procedure add_doubles
end interface
...
subroutine add_ints(a, b)
integer :: a, b
print *, "sum = ", (a + b)
end subroutine
subroutine add_doubles(a, b)
double precision :: a, b
print *, "sum = ", (a + b)
end subroutine
This is the good old static dispatch.

Related

Math Parser for Complex Numbers in C (ExprTk)

I have been using the ExprTk library quite frequently in the past in order to further process large output files generated with Mathematica (containing mathematical expressions) in C.
Until now, I exclusively used this library to process expressions that yield values of the type <double>, for which the library works flawlessly by defining the types
typedef exprtk::symbol_table<double> symbol_table_t;
typedef exprtk::expression<double> expression_t;
typedef exprtk::parser<double> parser_t;
and storing "everything" in a struct
struct readInExpression
{
double a, b;
symbol_table_t symbol_table;
expression_t expression;
};
Reading in a text file that contains the variables a and b as well as e.g. the user-defined function
double my_function(double a, double b) {
return a+b;
}
can be achieved by means of
void readInFromFile(readInExpression* f, parser_t* p) {
std::string file = "xyz.txt";
std::ifstream ifs(file);
std::string content( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
f->symbol_table.add_variable("a",f->a);
f->symbol_table.add_variable("b",f->b);
f->symbol_table.add_function("my_function",my_function);
f->expression.register_symbol_table(f->symbol_table);
p->compile(content,f->expression);
}
One may then evaluate the read-in expression for arbitrary values of a and b by using
double evaluateFile(readInExpression* f, double a, double b) {
f->a = a;
f->b = b;
return f->expression.value();
}
Recently, I ran into problems when trying to process text files that contain complex numbers and functions that return complex values of the type std::complex<double>. More specifically, I have a .txt file that contains expressions of the form
2*m*A0(m*m) + Complex(1.0,2.0)*B0(M*M,0.0,m*m)
where A0(a) and B0(a,b,c) are the scalar loop integrals that arise from the Passarino-Veltman reduction of (tensor) loop integrals in high-energy physics.
These can be evaluated numerically in C using LoopTools, where it is to be noted that they take complex values for certain values of a, b, and c. Simply replacing <double> by std::complex<double> in the typedefs above throws tons of errors when compiling. I am not sure whether the ExprTk library is able to handle complex numbers at all -- I know that it cannot deal with custom classes, but from what I understand, it should be able to handle native datatypes (as I found here, ExprTk is able to at least deal with vectors, but given the complexity of the expressions I need to process, I do not think it will be possible to somehow rewrite everything in form of vectors, in particular due to the difference in doing algebra with complex numbers and vectors). Note that neither can I split the expressions into real and imaginary part because I have to evaluate the expressions for many different values of the variables.
Although I dealt with complex numbers and the mentioned functions A0(a) and B0(a,b,c) in text files before, I solved this by simply including the .txt files in C using #include "xyz.txt", implemented in a corresponding function, which, however, seems impossible given the size of the text files at hand (the compiler throws an error if I try to do so).
Does anybody know if and how ExprTk can deal with complex numbers? (A MWE would be highly appreciated.) If that is not the case, can anyone here suggest a different math parser that is user friendly and can deal with complex numbers of the type std::complex<double>, at the same time allowing to define custom functions that themselves return such complex values?
A MWE:
/************/
/* Includes */
/************/
#include <iostream> // Input and Output on the console
#include <fstream> // Input and Output to files
#include <string> // In order to work with strings -- needed to loop through the Mathematica output files
#include "exprtk.hpp" // Parser to evaluate string expressions as mathematical/arithmetic input
#include <math.h> // Simple Math Stuff
#include <gsl/gsl_math.h> // GSL math stuff
#include <complex> // Complex Numbers
/**********/
/* Parser */
/**********/
// Type definitions for the parser
typedef exprtk::symbol_table<double> symbol_table_t; // (%)
typedef exprtk::expression<double> expression_t; // (%)
typedef exprtk::parser<double> parser_t; // (%)
/* This struct is used to store certain information of the Mathematica files in
order to later evaluate them for different variables with the parser library. */
struct readInExpression
{
double a,b; // (%)
symbol_table_t symbol_table;
// Instantiate expression
expression_t expression;
};
/* Global variable where the read-in file/parser is stored. */
readInExpression file;
parser_t parser;
/*******************/
/* Custom function */
/*******************/
double my_function(double a, double b) {
return a+b;
}
/***********************************/
/* Converting Mathematica Notation */
/***********************************/
/* Mathematica prints complex numbers as Complex(x,y), so we need a function to convert to C++ standard. */
std::complex<double> Complex(double a, double b) { // (%)
std::complex<double> c(a,b);
return c;
}
/************************************/
/* Processing the Mathematica Files */
/************************************/
double evaluateFileDoubleValuedInclude(double a, double b) {
return
#include "xyz.txt"
;
}
std::complex<double> evaluateFileComplexValuedInclude(double a, double b) {
return
#include "xyzC.txt"
;
}
void readInFromFile(readInExpression* f, parser_t* p) {
std::string file = "xyz.txt"; // (%)
std::ifstream ifs(file);
std::string content( (std::istreambuf_iterator<char>(ifs) ),
(std::istreambuf_iterator<char>() ) );
// Register variables with the symbol_table
f->symbol_table.add_variable("a",f->a);
f->symbol_table.add_variable("b",f->b);
// Add custom functions to the evaluation list (see definition above)
f->symbol_table.add_function("my_function",my_function); // (%)
// f->symbol_table.add_function("Complex",Complex); // (%)
// Register symbol_table to instantiated expression
f->expression.register_symbol_table(f->symbol_table);
// Compile the expression with the instantiate parser
p->compile(content,f->expression);
}
std::complex<double> evaluateFile(readInExpression* f, double a, double b) { // (%)
// Set the values of the struct to the input values
f->a = a;
f->b = b;
// Evaluate the result for the upper values
return f->expression.value();
}
int main() {
exprtk::symbol_table<std::complex<double> > st1; // Works
exprtk::expression<std::complex<double> > e1; // Works
// exprtk::parser<std::complex<double> > p1; // Throws an error
double a = 2.0;
double b = 3.0;
std::cout << "Evaluating the text file containing only double-valued functions via the #include method: \n" << evaluateFileDoubleValuedInclude(a,b) << "\n \n";
std::cout << "Evaluating the text file containing complex-valued functions via the #include method: \n" << evaluateFileComplexValuedInclude(a,b) << "\n \n";
readInFromFile(&file,&parser);
std::cout<< "Evaluating either the double-valued or the complex-valued file [see the necessary changes tagged with (%)]:\n" << evaluateFile(&file,a,b) << "\n";
return 0;
}
xyz.txt
a + b * my_function(a,b)
xyzC.txt
2.0*Complex(a,b) + 3.0*a
To get the MWE to work, put the exprtk.hpp file in the same folder where you compile.
Note that the return type of the evaluateFile(...) function can be/is std::complex<double>, even though only double-valued types are returned. Lines tagged with // (%) are subject to change when trying out the complex-valued file xyzC.txt.
Instantiating exprtk::parser<std::complex<double> > throws (among others)
./exprtk.hpp:1587:10: error: no matching function for call to 'abs_impl'
exprtk_define_unary_function(abs )
while all other needed types seem to not complain about the type std::complex<double>.
I actually know next to nothing about ExprTk (just what I just read in its documentation and a bit of its code -- EDIT: now somewhat more of its code), but it seems to me unlikely that you'll be able to accomplish what you want without doing some major surgery to the package.
The basis of its API, as you demonstrate in your question, are template objects specialised on a single datatype. The documentation says that that type "…can be any floating point type. This includes… any custom type conforming to an interface comptaible (sic) with the standard floating point type." Unfortunately, it doesn't clarify what they consider the interface of the standard floating point type to be; if it includes every standard library function which could take a floating point argument, it's a very big interface indeed. However, the distribution includes the adaptor used to create a compatible interface for the MPFR package which gives some kind of idea what is necessary.
But the issue here is that I suspect you don't want an evaluator which can only handle complex numbers. It seems to me that you want to be able to work with both real and complex numbers. For example, there are expressions which are unambiguous for real numbers and somewhat arbitrary for complex numbers; these include a < b and max(a, b), neither of which are implemented for complex types in C++. However, they are quite commonly used in real-valued expressions, so just eliminating them from the evaluation language would seem a bit arbitrary. [Note 1] ExprTK does assume that the numeric type is ordered for some purposes, including its incorrect (imho) delta equality operator, and those comparisons are responsible for a lot of the error messages which you are receiving.
The ExprTK header does correctly figure out that std::complex<double> is a complex type, and tags it as such. However, no implementation is provided for any standard function called on complex numbers, even though C++ includes implementations for many of them. This absence is basically what triggers the rest of the errors, including the one you mention for abs, which is an example of a math function which C++ does implement for complex numbers. [Note 2]
That doesn't mean that there is no solution; just that the solution is going to involve a certain amount of work. So a first step might be to fill in the implementations for complex types, as per the MPFR adaptor linked to above (although not everything goes through the _impl methods, as noted above with respect to ordered comparison operators).
One option would be to write your own "real or complex" datatype; in a simple implementation, you could use a discriminated union like:
template<typename T>
class RealOrComplex {
public:
RealOrComplex(T a = 0)
: is_complex_(false), value_.real(a) {}
RealOrComplex(std::complex<T> a)
: is_complex_(true), value_.cplx(a) {}
// Operator implementations, omitted
private:
bool is_complex_;
union {
T real;
std::complex<T> cmplx;
} value_;
};
A possible simpler but more problematic approach would be to let a real number simply be a complex number whose imaginary part is 0 and then write shims for any missing standard library math functions. But you might well need to shim a large part of the Loop library as well.
So while all that is doable, actually doing it is, I'm afraid, too much work for an SO answer.
Since there is some indication in the ExprTK source that the author is aware of the existence of complex numbers, you might want to contact them directly to ask about the possibility of a future implementation.
Notes
It seems that Mathematica throws an error, if these operations are attempted on complex arguments. On the other hand, MatLab makes an arbitrary choice: ordered comparison looks only at the real part, but maximum is (inconsistently) handled by converting to polar coordinates and then comparing component-wise.
Forcing standard interfaces to be explicitly configured seems to me to be a curious implementation choice. Surely it would have been better to allow standard functions to be the default implementation, which would also avoid unnecessary shims like the explicit reimplementation of log1p and other standard math functions. (Perhaps these correspond to known inadequacies in certain math libraries, though.)
... can anyone here suggest a different math parser that is user friendly and can deal with complex numbers of the type std::complex(double), at the same time allowing to define custom functions that themselves return such complex values?
I came across only one math parser that handled complex numbers, Foreval:
https://sourceforge.net/projects/foreval/
Implementation as dll library.
You can connect real and complex variables of the "double" and "extended" type to Foreval in any form, passing the addresses of the variables.
Has built-in standard functions with complex variables. Also, you can connect external functions with complex variables.
But only the type of complex variables, passed and returned in functions is own, internal and will be different from std::complex(double).
There are examples for GCC in the source.
There are two disadvantages:
There is only a 32-bit version of Foreval.dll (connection is possible only for 32-bit program).
And only for OS Windows.
But there are also advantages:
Foreval.dll is a compiler, that generates machine code (fast calculations).
There is a real type with floating point - "extended" ("double" is too), also for complex numbers.

Compiling fortran and C++ program and linking from intel compiler

I have a Fortran main program under which there are many subroutines. One of the subroutine calls a c++ function. That c++ function is calling another Fortran subroutine. Now I need to compile all of them together to get the output.
I have tried to compile c++ file with icl. Then I have used ifort as a linker between Fortran file and object file created for the c++. But the method is not working. Its showing unresolved external symbol.
I expect that you at least saw this: https://software.intel.com/en-us/node/691954
What they wrote there mostly refers to C, though there is mention of C++ libraries. IF you link with C++ ocde, you need those.
You should read about symbol name mangling in C++. Because C++ supports overloaded funktions but linker requires unique symbols, C++ generates
something like _foo****#8 instead of foo for a function foo(int i, float j), where * depend on compiler and on type of arguments.
Fortran code generates C-styled symbols if BIND(C) used, you can force C++ to generate one for a function , by using extern "C" in C++ code both for prototypes of fortran functions called from C++ and for functions that will be called from fortran.
This example works with C compiler, but for C++ you need to change symbol generated (https://software.intel.com/en-us/node/691929#92BDCE7A-30FA-4A60-BCDB-7CE1521572EC). Note that C and Fortran interoperability isn't standardized and usually not portable from one compiler set to another. I had to deal with problem that Compaq compiler was mangling function names as well but not in C++ way, or that PGI Fortran required stdcall conventions.
Fortran Code Example
subroutine Simulation(alpha, beta, gamma, delta, arrays) BIND(C)
use, intrinsic :: ISO_C_BINDING
implicit none
integer (C_LONG), value :: alpha
real (C_DOUBLE), intent(inout) :: beta
integer (C_LONG), intent(out) :: gamma
real (C_DOUBLE),dimension(*),intent(in) :: delta
type, BIND(C) :: pass
integer (C_INT) :: lenc, lenf
type (C_PTR) :: c, f
end type pass
type (pass), intent(inout) :: arrays
real (C_FLOAT), ALLOCATABLE, target, save :: eta(:)
real (C_FLOAT), pointer :: c_array(:)
...
! Associate c_array with an array allocated in C
call C_F_POINTER (arrays%c, c_array, (/arrays%lenc/) )
...
! Allocate an array and make it available in C
arrays%lenf = 100
ALLOCATE (eta(arrays%lenf))
arrays%f = c_loc(eta)
...
end subroutine Simulation
C Struct declaration Example
struct pass {int lenc, lenf; float *c, *f;};
C Function Prototype Example
void simulation(long alpha, double *beta,
long *gamma, double delta[], struct pass *arrays);
C Calling sequence Example
simulation(alpha, &beta, &gamma, delta, &arrays);

Convert block data F77 to F90

I'm converting some F77 files to F90. However, there are some common blocks that did not converted. I'm a novice in F90 and have no experience in F77.
Could someone show me how to covert the following example code to F90?
BLOCK DATA SETUP
INTEGER A,B,C
REAL I,J,K,L
COMMON /AREA1/ A,B,C
COMMON /AREA2/ I,J,K,L
DATA A,B,C,I,J,K,L/0,1,2,10.0,-20.0,30.0,-40.0/
END
My idea is to put the arrays A, B, and C in a module. The main thing I don't get here is the AREA1 and AREA2. How are these used in F77 and how do I translate those? My first guess is to discard them and simply define A,B, & C in the module. However, are they a kind of derive type within which A, B, & C are contained?
First up, the original code should compile in Fortran 90 and later. So if it isn't broken, don't try to fix it.
COMMON blocks are basically global variables. In every procedure that the global variables are used, they have to be declared in the same way1, and then they are shared everywhere. Something like this:
integer a, b
common /globals/ a, b
A more modern approach would be to convert globals into a module:
module globals
implicit none
integer a, b
end module globals
And then use that module everywhere you need access to a and b
program main
use globals
implicit none
a = 4
b = 2
end program main
You could either put the DATA statement into the module, or, even easier, initialise every variable in the declaration:
module AREA1
implicit none
integer :: a = 0
integer :: b = 1
integer :: c = 2
end module AREA1
module AREA2
implicit none
real :: i = 10.0
real :: j = -20.0
real :: k = 30.0
real :: l = -40.0
end module AREA2
Then, you can replace the whole thing by just use AREA1 and use AREA2 before the implicit none everywhere you need access to their variables.
Edit: Forgot the footnote
1The rules for common blocks are more flexible, in that the values for the different variables are stored in a common memory location, in the order that they are named. So while it is not technically necessary to always use the same COMMON statement, you can very easily introduce bugs if you don't.
If you have differently named variables (but of the same type), then adapting that is not that hard. Say you have
integer a, b
common /globals/ a, b
in the main program and
integer i, j
common /globals/ i, j
in a subroutine. Assuming that you create a module with a and b, you can then in the subroutine use it in this way:
use globals, only: i => a, j => b
(Note that if you use only, you have to list every variable that you want to use out of the module. You could use something like: only: a, i => b if you want a and i.)
Of course, the following would also be compatible with the previous globals common block, but might lead to more trouble:
integer k(2)
common /globals/ k

the run time aborting when calling c++ sub from fortran

I had read many posts here about mixing languages use of Fortran and C++. However, I'm still stuck with my current problem: my Fortran program always aborted.
I have the Fortran program: test-cc.f90 and the C++ program: deb_cc.cc.
deb_cc.cc contains:
#include <iostream>
using namespace std;
extern "C" void deb_cc_(float*** rh,int* x, int* y , int* z_ext )
{
cout <<"thinkdeb 1"<<endl;
int i, j, k;
cout <<"thinkdeb 1"<<endl;
cout <<"thinktest i=8,j=4,k=1"<< " (*x) " << (*x)<<endl;
cout <<"thinktest i=8,j=4,k=1"<< " x3/rh " << rh[1][1][1]<<endl; //abortion
// here
cout <<"thinkdeb 7"<<endl;
return;
}//end function
test-cc.f90 contains:
use ISO_C_BINDING
implicit none
interface
subroutine deb_cc( rh,x,y,z_ext)
use ISO_C_BINDING
implicit none
real(c_float),allocatable::rh(:,:,:)
integer(c_int):: x,y,z_ext
end subroutine
end interface
integer nx,ny,nz
parameter (nx=10,ny=10,nz=10)
real ,dimension (:,:,:),allocatable:: x1
integer:: iy1,iy2,iy3,iy4
integer i,j,k
allocate(x1(nx,ny,nz))
do k=1,nz
do j=1,ny
do i=1,nx
x1(i,j,k)=k*1000+j*100+i
enddo
enddo
enddo
iy1=nx
iy2=ny
iy3=nz
call deb_cc(x1,iy1,iy2,iy3)
end
I compiled them by pgf90 -c test-cc.f90 and pgcpp -c deb_cc.cc
Finally, I linked them by pgf90 -pgcpplibs test-cc.o deb_cc.o.
The output is:
thinktest in test- x1 (8,2,2) is 2208.000
thinkdeb 1
thinkdeb 1
thinktest i=8,j=4,k=1 (*x) 10
Segmentation fault (core dumped)
You use the iso_c_binding module, but your procedure interface is not C interoperable.
The iso_c_binding module is not the most important thing. The bind(C) attribute is the key. (I ranted several times about the unfortunate name of the tag here)
You use an assumed shape allocatable array argument
real(c_float),allocatable::rh(:,:,:)
these are not allowed in interoperable procedures in Fortran 2008, because C or C++ have no idea what to do with them. They are not just addresses. If you used the bind(C) attribute in the interface, the compiler should tell you it is wrong.
There is a possibility to pass them in the next Fortran standard (in an existing TS actually) using a special C header, but some compilers (notably gfortran) are still not compatible.
As you do not do any reallocation on the C side (at least in your example), you can just pass the array as an assumed size (array(*)) argument. I also changed the C++ name, no need for the underscore.
interface
subroutine deb_cc(rh,x,y,z_ext) bind(C, name="deb_cc")
use ISO_C_BINDING
real(c_float) :: rh(*)
integer(c_int):: x,y,z_ext
end subroutine
end interface
On the C side, you cannot use the C arrays which are pointers to pointers ([i][j][k]). What you receive from Fortran is a single block of memory. You also have to pass the array shape. At least in the first two Fortan dimensions.
I would just use a macro to index the array in C.
// adjust as needed, many variants possible
#define IND(i,j,k) = i + (j-1) * nx + (k-1) * nx * ny
// adjust as needed, many variants possible
extern "C" void deb_cc(float *rh, int *nx, int *ny, int *nz) {
cout <<"thinktest i=8,j=4,k=1"<< " x3/rh " << rh(IND(8,4,1))<<endl;
}

send mpi message from a c++ code to fortran 90 code

I am try to see if I can send the contents of an array in a c++ code to a fortran 90 code. I'm using openmpi 1.4.3 built using intel 11.1.072 compilers. They are installed on Linux version 2.6.18-108chaos (mockbuild#chaos4builder1) (gcc version 4.1.2 20080704 (Red Hat 4.1.2-48)).
Here is the c++ side:
# include <cstdlib>
# include <iostream>
# include <mpi.h>
using namespace std;
void printarray (float arg[], int length) {
for (int n=0; n<length; n++)
cout << arg[n] << " ";
cout << "\n";
}
int main(int argc, char *argv[] ){
float a[10];
int myrank,i;
MPI::Init ( argc, argv );
myrank=MPI::COMM_WORLD.Get_rank();
cout << "rank "<<myrank<<" is c++ rank."<<std::endl;
for (i=0;i<10;i++){
a[i]=10.0;
}
printarray(a,10);
MPI::COMM_WORLD.Send(&a[0],1,MPI::DOUBLE_PRECISION,1,100);
MPI::Finalize();
}
and here is the f90 side:
program main
implicit none
include "mpif.h"
integer:: ierr,stat(MPI_STATUS_SIZE)
real(8):: a(10)
call mpi_init(ierr)
a=0
print*,a
call mpi_recv(a(1),10,MPI_DOUBLE_PRECISION,0,100,MPI_COMM_WORLD,stat,ierr)
print*,a
call mpi_finalize(ierr)
end program
after I've compiled the two codes, I run with
$mpirun -n 1 *c_executable* : -n 1 *fortran_executable* > output
The numbers I get on the fortran side are not 10.0.
The MPI standard indeed has provisions for language interoperability - the whole §16.3 of the MPI 2.2 document is dedicated to language interoperability between Fortran and C.
§16.3.10 Interlanguage Communication
The type maching rules for communications in MPI anr not changed: the datatype specification for each item sent should match, in type signature, the datatype specification used to receive this item (unless one of the types is MPI_PACKED). Also, the type of a message item should match the type declaration for the corresponding communication buffer location, unless the type is MPI_BYTE or MPI_PACKED. Interlanguage communication is allowed if it complies with these rules.
Then it goes on to show an example where the same construced datatype is used to send a message from a Fortran code and to receive it in a piece of C code. The type is constructed so as to allow the C code to receive the data into a buffer that belongs to the Fortran code, but what is more relevant to your question is that the C code uses a datatype that was constructed from the Fortran MPI_REAL. Using Fortran datatypes in C functions and vice versa is perfectly legal if it makes sense:
§16.3.6 MPI Opaque Objects - Datatypes
... If a datatype defined in one language is used for a communication call in another language, then the message sent will be identical to the message that would be sent from the first language: the same communication buffer is accessed, and the same representation conversion is performed, if needed. All predefined datatypes can be used in datatype constructors in any language. If a datatype is committed, it can be used for communication in any language.
(predefined MPI datatypes like MPI_REAL and MPI_DOUBLE are committed)
On the contrary, using Fortran datatypes on the one side and C datatypes on the other is allowed but considered not portable:
§16.3.10 Interlanguage Communication
... MPI implementations may weaken these type matching rules, and allow messages to be sent with Fortran types and received with C types, and vice versa, when those types match. I.e., if the Fortran type INTEGER is identical to the C type int, then an MPI implementation may allow data to be sent with datatype MPI_INTEGER and be received with datatype MPI_INT. However, such code is not portable.
(emphasis mine)
Changing REAL(8) to DOUBLE PRECISION does nothing to increase the portablity of your code as the Fortran standard guarantees nothing about the representation of the DOUBLE PRECISION type - it only says that DOUBLE PRECISION is an alternative specifier for one kind of REAL type, namely the double precision kind, which should have greater decimal precision than the default real. Sending REAL(8) with a datatype of MPI_DOUBLE_PRECISION is not portable. Instead a portable program would use the SELECTED_REAL_KIND intrinsic of Fortran together with MPI_Type_create_f90_real to register a matching MPI datatype.
The best option IMHO is to rely on the language interoperability between C and Fortran and stick to the same datatypes on both sides. Since your compiler suite is recent enough, you can use the ISO_C_BINDING mechanism of Fortran to get REAL and INTEGER kinds, compatible with C, and use the C datatypes in the Fortran calls. For example:
USE, INTRINSIC :: ISO_C_BINDING
REAL(C_DOUBLE), DIMENSION(10) :: darray
INTEGER(C_INT) :: ival
...
CALL MPI_SEND(darray, 10, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD, ierr)
CALL MPI_BCAST(ival, 1, MPI_INT, 0, MPI_COMM_WORLD, ierr)
...
Yes, you can do this; the main problem is that in your C++ code, your a array is of type float, not double.
You're also only sending 1, not 10, of these not-doubles; the MPI_RECV() would still work, but of course the other 9 values wouldn't be set.
Something else that you should note is that you should use MPI_DOUBLE in C/C++, and MPI_DOUBLE_PRECISION in Fortran; they need not be the same, and in fact I imagine the use of MPI_DOUBLE_PRECISION in C is undefined.
You also probably want to use double precision in the fortran program rather than real(8), which is common but not standard.
In principle, you would even want to worry about heterogeneity, about the encoding of the floating point numbers on the machines running the two programs, but for most of us this isn't an issue.
Here is a modified working version in C
#include <stdio.h>
#include <mpi.h>
main(int argc, char **argv)
{
int i,ierr, num_procs, my_id;
double a[10];
for (i=0;i<10;i++)
{
a[i]=10.0;
}
ierr = MPI_Init(&argc, &argv);
printf(" Hello C Code\n");
/**/
ierr = MPI_Comm_rank(MPI_COMM_WORLD, &my_id);
ierr = MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
ierr = MPI_Send(&a[0],10,MPI_DOUBLE,1,100, MPI_COMM_WORLD);
ierr = MPI_Finalize();
}
Here is a modified working version in F
program main
use mpi
implicit none
integer:: ierr,stat(MPI_STATUS_SIZE)
double precision:: a(10)
call mpi_init(ierr)
write(*,*)"Hello F Code"
a=0
print*,a
call mpi_recv(a(1),10,MPI_DOUBLE_PRECISION,0,100,MPI_COMM_WORLD,stat,ierr)
print*,a
call mpi_finalize(ierr)
end program