/*
comm2.c (MPI)
*/

#include "oth.h"
#include "oth_mpi.h"

#ifdef _MPI
#include "mpi.h"
#endif

// share boundary
void comm_boundary(d_complex_t *v)
{
#ifdef _MPI
	MPI_Status status;
	const int tag = 0;

	// -X direction
	if (commRank > 0) {
		// copy to send buffer
		memcpy(Sendcomplex_m, &v[Send0_m], Sendcount_m * sizeof(d_complex_t));
		for (int64_t n = 0; n < Sendcount_m; n++) {
			Sendbuf_m[(2 * n) + 0] = Sendcomplex_m[n].r;
			Sendbuf_m[(2 * n) + 1] = Sendcomplex_m[n].i;
		}
		// MPI
		int dst = commRank - 1;
		MPI_Sendrecv(Sendbuf_m, 2 * Sendcount_m, MPI_DOUBLE, dst, tag,
		             Recvbuf_m, 2 * Recvcount_m, MPI_DOUBLE, dst, tag, MPI_COMM_WORLD, &status);
		// copy from recv buffer
		for (int64_t n = 0; n < Recvcount_m; n++) {
			 Recvcomplex_m[n].r = Recvbuf_m[(2 * n) + 0];
			 Recvcomplex_m[n].i = Recvbuf_m[(2 * n) + 1];
		}
		memcpy(&v[Recv0_m], Recvcomplex_m, Recvcount_m * sizeof(d_complex_t));
	}

	// +X direction
	if (commRank < commSize - 1) {
		// copy to send buffer
		memcpy(Sendcomplex_p, &v[Send0_p], Sendcount_p * sizeof(d_complex_t));
		for (int64_t n = 0; n < Sendcount_p; n++) {
			Sendbuf_p[(2 * n) + 0] = Sendcomplex_p[n].r;
			Sendbuf_p[(2 * n) + 1] = Sendcomplex_p[n].i;
		}
		// MPI
		int dst = commRank + 1;
		MPI_Sendrecv(Sendbuf_p, 2 * Sendcount_p, MPI_DOUBLE, dst, tag,
		             Recvbuf_p, 2 * Recvcount_p, MPI_DOUBLE, dst, tag, MPI_COMM_WORLD, &status);
		// copy from recv buffer
		for (int64_t n = 0; n < Recvcount_p; n++) {
			 Recvcomplex_p[n].r = Recvbuf_p[(2 * n) + 0];
			 Recvcomplex_p[n].i = Recvbuf_p[(2 * n) + 1];
		}
		memcpy(&v[Recv0_p], Recvcomplex_p, Recvcount_p * sizeof(d_complex_t));
	}
#endif
}

// X-PBC
void comm_Xpbc(d_complex_t *v)
{
#ifdef _MPI
	MPI_Status status;
	const int tag = 0;

	// -X boundary
	if (commRank == 0) {
		// copy to send buffer
		memcpy(Sendcomplex_Xpbc_m, &v[Send0_Xpbc_m], Sendcount_Xpbc_m * sizeof(d_complex_t));
		for (int64_t n = 0; n < Sendcount_Xpbc_m; n++) {
			Sendbuf_Xpbc_m[(2 * n) + 0] = Sendcomplex_Xpbc_m[n].r;
			Sendbuf_Xpbc_m[(2 * n) + 1] = Sendcomplex_Xpbc_m[n].i;
		}
		// MPI
		int dst = commSize - 1;
		MPI_Sendrecv(Sendbuf_Xpbc_m, 2 * Sendcount_Xpbc_m, MPI_DOUBLE, dst, tag,
		             Recvbuf_Xpbc_m, 2 * Recvcount_Xpbc_m, MPI_DOUBLE, dst, tag, MPI_COMM_WORLD, &status);
		// copy from recv buffer
		for (int64_t n = 0; n < Recvcount_Xpbc_m; n++) {
			Recvcomplex_Xpbc_m[n].r = Recvbuf_Xpbc_m[(2 * n) + 0];
			Recvcomplex_Xpbc_m[n].i = Recvbuf_Xpbc_m[(2 * n) + 1];
		}
		memcpy(&v[Recv0_Xpbc_m], Recvcomplex_Xpbc_m, Recvcount_Xpbc_m * sizeof(d_complex_t));
	}

	// +X boundary
	if (commRank == commSize - 1) {
		// copy to send buffer
		memcpy(Sendcomplex_Xpbc_p, &v[Send0_Xpbc_p], Sendcount_Xpbc_p * sizeof(d_complex_t));
		for (int64_t n = 0; n < Sendcount_Xpbc_p; n++) {
			Sendbuf_Xpbc_p[(2 * n) + 0] = Sendcomplex_Xpbc_p[n].r;
			Sendbuf_Xpbc_p[(2 * n) + 1] = Sendcomplex_Xpbc_p[n].i;
		}
		// MPI
		int dst = 0;
		MPI_Sendrecv(Sendbuf_Xpbc_p, 2 * Sendcount_Xpbc_p, MPI_DOUBLE, dst, tag,
		             Recvbuf_Xpbc_p, 2 * Recvcount_Xpbc_p, MPI_DOUBLE, dst, tag, MPI_COMM_WORLD, &status);
		// copy from recv buffer
		for (int64_t n = 0; n < Recvcount_Xpbc_p; n++) {
			Recvcomplex_Xpbc_p[n].r = Recvbuf_Xpbc_p[(2 * n) + 0];
			Recvcomplex_Xpbc_p[n].i = Recvbuf_Xpbc_p[(2 * n) + 1];
		}
		memcpy(&v[Recv0_Xpbc_p], Recvcomplex_Xpbc_p, Recvcount_Xpbc_p * sizeof(d_complex_t));
	}
#endif
}
