[Pw_forum] compile as a C++ library (prototype)
Denis Davydov
davydden at gmail.com
Mon Apr 8 18:35:02 CEST 2013
Dear all,
After some trial and error, following advices given here, i come up with the solution on how to make a c++ library from PW with a controllable MPI communicator. Everything compiles fine with a small example, but i did not yet implement passing input file name.
In a hope that it will be useful / interesting for other users / developers, i write a quick list of how to achieve it below.
Things can definitely be made more pretty, i would be grateful for any advices.
Maybe a more clean version of this can make it to a release one day. I think such an interface makes it easier to combine different codes while having a full control over MPI.
.check_pw.x.j runs fine so far. I did not try anything else yet.
I hope the content below is appropriate for this mailing list, please, excuse me if it is not.
HOWTO:
1. pwscf.f90 -- i wrapped the main function in another function.
PROGRAM pwscf
USE parallel_include
!
INTEGER :: comm = mpi_comm_world
INTEGER :: sz
CHARACTER(len=256) ::name
INTEGER :: do_init = 1
WRITE (*,*) ' pwscf do_init= ', do_init
CALL pwscf2(comm,do_init,name,sz)
END PROGRAM pwscf
SUBROUTINE pwscf2 (input_comm,do_init, in_string,in_size)
…
USE parallel_include
…
INTEGER, INTENT (IN) :: input_comm
CHARACTER(len=256), INTENT (IN) :: in_string
INTEGER, INTENT (IN) :: in_size
INTEGER, INTENT (IN) :: do_init
#ifdef __MPI
!
CALL set_mp_comm(input_comm, do_init)
…
2. In parallel_include.f90 the last function in the above is defined as:
...
INTEGER, PUBLIC :: qe_mp_world = mpi_comm_world
LOGICAL, PUBLIC :: do_mpi_init = .TRUE.
…
CONTAINS
SUBROUTINE set_mp_comm(comm, do_init)
IMPLICIT NONE
INTEGER, INTENT(IN) :: comm
INTEGER, INTENT(IN) :: do_init
do_mpi_init = (do_init.EQ.1)
qe_mp_world = comm
RETURN
END SUBROUTINE set_mp_comm
3. In mp.f90 and mp_global.f90 i replaced all the occurrence of mpi_comm_world with a new
communicator qe_mp_world, which by default is equal to mpi_comm_world.
In addition MPI_Init and MPI_Finalized are wrapped in IF statement, e.g.
IF (do_mpi_init) CALL mpi_init(ierr).
We don't want to run those if MPI was initialized already externally.
4. a c++ wrapper looks like:
#include "pw.h"
extern"C" {
void pwscf2_(int * comm,int *do_init , char *file, int * size);
}
void qe_run(char *name, MPI_Comm my_comm )
{
MPI_Fint fcomm;
fcomm = MPI_Comm_c2f(my_comm);
int size = sizeof(name);
int do_init = 0;
pwscf2_(&fcomm, &do_init, name, &size);
}
with a trivial header:
#include "mpi.h"
void qe_run(char *name, MPI_Comm my_comm );
The whole thing can be run as:
#include "pw.h"
using namespace std;
int
main(int argc, char* argv[])
{
// Initialize the MPI library:
MPI::Init(argc, argv);
int me,nprocs;
MPI_Comm_rank(MPI_COMM_WORLD,&me);
MPI_Comm_size(MPI_COMM_WORLD,&nprocs);
char name [] = "my_input.in";
qe_run(name, MPI_COMM_WORLD);
// Tell the MPI library to release all resources it is using:
MPI::Finalize();
return 0;
}
5. Compiling:
All the c++ files are compiled in a usual way with mpic++.
The wrapper-library is compiled within PW/Makefile using:
MPI_LINK_FLAGS = $(shell mpic++ --showme:link)
CPP_LINK_FLAGS = -L/opt/local/lib/gcc47/ -lstdc++
libpwc++.a : pw.x
$(LD) -shared -fpic $(LDFLAGS) pw.o $(PWOBJS) libpw.a $(QEMODS) $(LIBOBJS) $(LIBS) $(MPI_LINK_FLAGS) $(CPP_LINK_FLAGS) -o $@
I did not yet look at how to exactly to pass the input file,
but that should not be a big deal anyway.
Kind regards,
Denis
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.quantum-espresso.org/pipermail/users/attachments/20130408/62203fb5/attachment.html>
More information about the users
mailing list