[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