Program Listing for File electroMotiveForce.cpp
↰ Return to documentation for file (hydro/electromotiveforce/electroMotiveForce.cpp
)
// ***********************************************************************************
// Idefix MHD astrophysical code
// Copyright(C) 2020-2022 Geoffroy R. J. Lesur <geoffroy.lesur@univ-grenoble-alpes.fr>
// and other code contributors
// Licensed under CeCILL 2.1 License, see COPYING for more information
// ***********************************************************************************
#include <string>
#include "electroMotiveForce.hpp"
#include "hydro.hpp"
#include "dataBlock.hpp"
#include "input.hpp"
// Initialisation of electromotive force object
ElectroMotiveForce::ElectroMotiveForce() {
// Do nothing
}
// Init the emf from a datablock pointer
void ElectroMotiveForce::Init(Input &input, Hydro *hydro) {
idfx::pushRegion("ElectroMotiveForce::Init");
#if MHD == YES
if(input.CheckEntry("Hydro","emf")>=0) {
std::string opType = input.Get<std::string>("Hydro","emf",0);
if(opType.compare("arithmetic")==0) {
this->averaging = arithmetic;
} else if(opType.compare("uct0")==0) {
this->averaging = uct0;
} else if(opType.compare("uct_contact")==0) {
this->averaging = uct_contact;
} else if(opType.compare("uct_hll")==0) {
this->averaging = uct_hll;
} else if(opType.compare("uct_hlld")==0) {
this->averaging = uct_hlld;
} else {
idfx::cout << "ElectroMotiveForce: unknown averaging scheme " << opType << std::endl;
IDEFIX_ERROR("Unknown EMF averaging scheme");
}
} else {
if(hydro->hallStatus.status == HydroModuleStatus::Disabled) {
// by default, use uct_contact
this->averaging = uct_contact;
} else {
this->averaging = arithmetic;
}
}
this->data = hydro->data;
this->hydro = hydro;
// Allocate shearing box arrays
if(hydro->haveShearingBox == true) {
sbEyL = IdefixArray2D<real>("EMF_sbEyL", data->np_tot[KDIR], data->np_tot[JDIR]);
sbEyR = IdefixArray2D<real>("EMF_sbEyR", data->np_tot[KDIR], data->np_tot[JDIR]);
sbEyRL = IdefixArray2D<real>("EMF_sbEyRL", data->np_tot[KDIR], data->np_tot[JDIR]);
}
D_EXPAND( ez = IdefixArray3D<real>("EMF_ez",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
,
ex = IdefixArray3D<real>("EMF_ex",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
ey = IdefixArray3D<real>("EMF_ey",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); )
D_EXPAND( ezi = IdefixArray3D<real>("EMF_ezi",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
ezj = IdefixArray3D<real>("EMF_ezj",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
,
exj = IdefixArray3D<real>("EMF_exj",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
exk = IdefixArray3D<real>("EMF_exj",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
eyi = IdefixArray3D<real>("EMF_eyi",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
eyk = IdefixArray3D<real>("EMF_eyi",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); )
if(averaging==uct_contact) {
D_EXPAND( svx = IdefixArray3D<real>("EMF_svx",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
svy = IdefixArray3D<real>("EMF_svy",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
svz = IdefixArray3D<real>("EMF_svz",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); )
}
if(averaging==uct_hll || averaging==uct_hlld) {
D_EXPAND( axL = IdefixArray3D<real>("EMF_axL",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
axR = IdefixArray3D<real>("EMF_axR",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
ayL = IdefixArray3D<real>("EMF_ayL",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
ayR = IdefixArray3D<real>("EMF_ayR",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
azL = IdefixArray3D<real>("EMF_azL",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
azR = IdefixArray3D<real>("EMF_azR",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); )
D_EXPAND( dxL = IdefixArray3D<real>("EMF_dxL",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
dxR = IdefixArray3D<real>("EMF_dxR",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
dyL = IdefixArray3D<real>("EMF_dyL",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
dyR = IdefixArray3D<real>("EMF_dyR",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); ,
dzL = IdefixArray3D<real>("EMF_dzL",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
dzR = IdefixArray3D<real>("EMF_dzR",
data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]); )
}
if(averaging==uct_hlld) {
if(hydro->mySolver == Solver::HLL || hydro->mySolver == Solver::TVDLF) {
IDEFIX_ERROR("HLLD EMF reconstruction is only compatible with HLLD or ROE Riemann solvers");
}
}
Ex1 = IdefixArray3D<real>("EMF_Ex1", data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
Ex2 = IdefixArray3D<real>("EMF_Ex2", data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
Ex3 = IdefixArray3D<real>("EMF_Ex3", data->np_tot[KDIR], data->np_tot[JDIR], data->np_tot[IDIR]);
// MPI initialisation
#ifdef WITH_MPI
Grid *mygrid = data->mygrid;
// init timer
this->timer.reset();
// Init exchange datasets
bufferSizeX1 = 0;
bufferSizeX2 = 0;
bufferSizeX3 = 0;
// in X1, we exchage ez
bufferSizeX1 = (data->np_int[JDIR]+JOFFSET) * data->np_int[KDIR];
#if DIMENSIONS == 3
// We also have ey
bufferSizeX1 += data->np_int[JDIR] * (data->np_int[KDIR]+KOFFSET);
#endif
BufferRecvX1[faceLeft ] = IdefixArray1D<real>("EmfRecvX1Left", bufferSizeX1);
BufferRecvX1[faceRight] = IdefixArray1D<real>("EmfRecvX1Right",bufferSizeX1);
BufferSendX1[faceLeft ] = IdefixArray1D<real>("EmfSendX1Left", bufferSizeX1);
BufferSendX1[faceRight] = IdefixArray1D<real>("EmfSendX1Right",bufferSizeX1);
// Number of cells in X2 boundary condition (only required when problem >2D):
#if DIMENSIONS >= 2
bufferSizeX2 = (data->np_int[IDIR]+IOFFSET) * data->np_int[KDIR];
#if DIMENSIONS == 3
// We also have ex
bufferSizeX2 += data->np_int[IDIR] * (data->np_int[KDIR]+KOFFSET);
#endif
BufferRecvX2[faceLeft ] = IdefixArray1D<real>("EmfRecvX2Left", bufferSizeX2);
BufferRecvX2[faceRight] = IdefixArray1D<real>("EmfRecvX2Right",bufferSizeX2);
BufferSendX2[faceLeft ] = IdefixArray1D<real>("EmfSendX2Left", bufferSizeX2);
BufferSendX2[faceRight] = IdefixArray1D<real>("EmfSendX2Right",bufferSizeX2);
#endif
// Number of cells in X3 boundary condition (only required when problem is 3D):
#if DIMENSIONS ==3
// ex
bufferSizeX3 = data->np_int[IDIR] * (data->np_int[JDIR]+JOFFSET);
// ey
bufferSizeX3 += (data->np_int[IDIR]+IOFFSET) * data->np_int[JDIR];
BufferRecvX3[faceLeft ] = IdefixArray1D<real>("EmfRecvX3Left", bufferSizeX3);
BufferRecvX3[faceRight] = IdefixArray1D<real>("EmfRecvX3Right",bufferSizeX3);
BufferSendX3[faceLeft ] = IdefixArray1D<real>("EmfSendX3Left", bufferSizeX3);
BufferSendX3[faceRight] = IdefixArray1D<real>("EmfSendX3Right",bufferSizeX3);
#endif // DIMENSIONS
// Init persistent MPI communications
int procSend, procRecv;
// X1-dir exchanges
// We receive from procRecv, and we send to procSend
MPI_SAFE_CALL(MPI_Cart_shift(mygrid->CartComm,0,1,&procRecv,&procSend ));
// Avoid the exchange when shearing box is enabled (so that EMFs don't get averaged)
if(data->rbound[IDIR] == shearingbox ) procSend = MPI_PROC_NULL;
if(data->lbound[IDIR] == shearingbox ) procRecv = MPI_PROC_NULL;
MPI_SAFE_CALL(MPI_Send_init(BufferSendX1[faceRight].data(), bufferSizeX1, realMPI, procSend, 100,
mygrid->CartComm, &sendRequestX1[faceRight]));
MPI_SAFE_CALL(MPI_Recv_init(BufferRecvX1[faceLeft].data(), bufferSizeX1, realMPI, procRecv, 100,
mygrid->CartComm, &recvRequestX1[faceLeft]));
// Send to the left
// We receive from procRecv, and we send to procSend
MPI_SAFE_CALL(MPI_Cart_shift(mygrid->CartComm,0,-1,&procRecv,&procSend ));
// Avoid the exchange when shearing box is enabled (so that EMFs don't get averaged)
if(data->lbound[IDIR] == shearingbox ) procSend = MPI_PROC_NULL;
if(data->rbound[IDIR] == shearingbox ) procRecv = MPI_PROC_NULL;
MPI_SAFE_CALL(MPI_Send_init(BufferSendX1[faceLeft].data(), bufferSizeX1, realMPI, procSend, 101,
mygrid->CartComm, &sendRequestX1[faceLeft]));
MPI_SAFE_CALL(MPI_Recv_init(BufferRecvX1[faceRight].data(), bufferSizeX1, realMPI, procRecv, 101,
mygrid->CartComm, &recvRequestX1[faceRight]));
#if DIMENSIONS >= 2
// We receive from procRecv, and we send to procSend
MPI_SAFE_CALL(MPI_Cart_shift(mygrid->CartComm,1,1,&procRecv,&procSend ));
MPI_SAFE_CALL(MPI_Send_init(BufferSendX2[faceRight].data(), bufferSizeX2, realMPI, procSend, 200,
mygrid->CartComm, &sendRequestX2[faceRight]));
MPI_SAFE_CALL(MPI_Recv_init(BufferRecvX2[faceLeft].data(), bufferSizeX2, realMPI, procRecv, 200,
mygrid->CartComm, &recvRequestX2[faceLeft]));
// Send to the left
// We receive from procRecv, and we send to procSend
MPI_SAFE_CALL(MPI_Cart_shift(mygrid->CartComm,1,-1,&procRecv,&procSend ));
MPI_SAFE_CALL(MPI_Send_init(BufferSendX2[faceLeft].data(), bufferSizeX2, realMPI, procSend, 201,
mygrid->CartComm, &sendRequestX2[faceLeft]));
MPI_SAFE_CALL(MPI_Recv_init(BufferRecvX2[faceRight].data(), bufferSizeX2, realMPI, procRecv, 201,
mygrid->CartComm, &recvRequestX2[faceRight]));
#endif
#if DIMENSIONS == 3
// We receive from procRecv, and we send to procSend
MPI_SAFE_CALL(MPI_Cart_shift(mygrid->CartComm,2,1,&procRecv,&procSend ));
MPI_SAFE_CALL(MPI_Send_init(BufferSendX3[faceRight].data(), bufferSizeX3, realMPI, procSend, 300,
mygrid->CartComm, &sendRequestX3[faceRight]));
MPI_SAFE_CALL(MPI_Recv_init(BufferRecvX3[faceLeft].data(), bufferSizeX3, realMPI, procRecv, 300,
mygrid->CartComm, &recvRequestX3[faceLeft]));
// Send to the left
// We receive from procRecv, and we send to procSend
MPI_SAFE_CALL(MPI_Cart_shift(mygrid->CartComm,2,-1,&procRecv,&procSend ));
MPI_SAFE_CALL(MPI_Send_init(BufferSendX3[faceLeft].data(), bufferSizeX3, realMPI, procSend, 301,
mygrid->CartComm, &sendRequestX3[faceLeft]));
MPI_SAFE_CALL(MPI_Recv_init(BufferRecvX3[faceRight].data(), bufferSizeX3, realMPI, procRecv, 301,
mygrid->CartComm, &recvRequestX3[faceRight]));
#endif
#endif // WITH_MPI
#endif // MHD==YES
idfx::popRegion();
}
// Destructor (clean up persistent communication channels)
ElectroMotiveForce::~ElectroMotiveForce() {
#if MHD == YES
#ifdef WITH_MPI
// Properly clean up the mess
idfx::cout << "Emf: Cleaning up MPI persistent communication channels" << std::endl;
for(int i=0 ; i< 2; i++) {
MPI_Request_free( &sendRequestX1[i]);
MPI_Request_free( &recvRequestX1[i]);
#if DIMENSIONS >= 2
MPI_Request_free( &sendRequestX2[i]);
MPI_Request_free( &recvRequestX2[i]);
#endif
#if DIMENSIONS == 3
MPI_Request_free( &sendRequestX3[i]);
MPI_Request_free( &recvRequestX3[i]);
#endif
}
#endif
#endif
}
void ElectroMotiveForce::ShowConfig() {
switch(averaging) {
case arithmetic:
idfx::cout << "ElectroMotiveForce: Using ARITHMETIC averaging scheme." << std::endl;
break;
case uct0:
idfx::cout << "ElectroMotiveForce: Using UCT0 averaging scheme." << std::endl;
break;
case uct_contact:
idfx::cout << "ElectroMotiveForce: Using UCT_CONTACT averaging scheme." << std::endl;
break;
case uct_hll:
idfx::cout << "ElectroMotiveForce: Using 2D-HLL averaging scheme." << std::endl;
break;
case uct_hlld:
idfx::cout << "ElectroMotiveForce: Using 2D-HLLD averaging scheme." << std::endl;
break;
default:
IDEFIX_ERROR("Unknown averaging scheme");
}
}