|
| 1 | +#ifdef __MPI |
| 2 | +#include "gtest/gtest.h" |
| 3 | +#include "gmock/gmock.h" |
| 4 | +#include "mpi.h" |
| 5 | +#include "module_base/global_variable.h" |
| 6 | +#include "src_parallel/parallel_kpoints.h" |
| 7 | + |
| 8 | +/************************************************ |
| 9 | + * unit test of functions in parallel_kpoints.cpp |
| 10 | + ***********************************************/ |
| 11 | + |
| 12 | +/** |
| 13 | + * The tested functions: |
| 14 | + * i. Parallel_Kpoints::init_pools() is the public interface |
| 15 | + * to call the private function Parallel_Kpoints::divide_pools(), |
| 16 | + * which divide all processes into KPAR groups. |
| 17 | + * ii.Parallel_Kpoints::kinf() is the public interface |
| 18 | + * to call another three functions: get_nks_pool(), |
| 19 | + * get_startk_pool(), get_whichpool(), which divide all kpoints |
| 20 | + * into KPAR groups. |
| 21 | + * The default number of processes is set to 6 in parallel_kpoints_test.sh. |
| 22 | + * One may modify it to do more tests, or adapt this unittest to local |
| 23 | + * environment. |
| 24 | + */ |
| 25 | + |
| 26 | +class ParaPrepare |
| 27 | +{ |
| 28 | +public: |
| 29 | + ParaPrepare(int KPAR_in,int nkstot_in): |
| 30 | + KPAR_(KPAR_in),nkstot_(nkstot_in){} |
| 31 | + int KPAR_; |
| 32 | + int nkstot_; |
| 33 | + void test_init_pools(void); |
| 34 | + void test_kinfo(const Parallel_Kpoints* Pkpts); |
| 35 | +}; |
| 36 | + |
| 37 | +void ParaPrepare::test_kinfo(const Parallel_Kpoints* Pkpts) |
| 38 | +{ |
| 39 | + int nks_pool_[KPAR_]={0}; |
| 40 | + int startk_pool_[KPAR_]={0}; |
| 41 | + int whichpool_[nkstot_]={0}; |
| 42 | + |
| 43 | + int quotient = nkstot_/KPAR_; |
| 44 | + int residue = nkstot_%KPAR_; |
| 45 | + // the previous "residue" pools have (quotient+1) kpoints |
| 46 | + for(int i=0;i<KPAR_;i++) |
| 47 | + { |
| 48 | + nks_pool_[i] = quotient; |
| 49 | + if(i<residue) |
| 50 | + { |
| 51 | + nks_pool_[i]++; |
| 52 | + } |
| 53 | + // number of kpoints in each pool |
| 54 | + EXPECT_EQ(Pkpts->nks_pool[i],nks_pool_[i]); |
| 55 | + // |
| 56 | + if(i>0) |
| 57 | + { |
| 58 | + startk_pool_[i]=startk_pool_[i-1]+nks_pool_[i-1]; |
| 59 | + } |
| 60 | + // the rank of the 1st process of each pool in MPI_COMM_WORLD |
| 61 | + EXPECT_EQ(Pkpts->startk_pool[i],startk_pool_[i]); |
| 62 | + // |
| 63 | + for(int ik=0;ik<nks_pool_[i];ik++) |
| 64 | + { |
| 65 | + int k_now = ik + startk_pool_[i]; |
| 66 | + // the pool where this kpoint (k_now) resides |
| 67 | + EXPECT_EQ(Pkpts->whichpool[k_now],i); |
| 68 | + } |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | + |
| 73 | +void ParaPrepare::test_init_pools() |
| 74 | +{ |
| 75 | + int* nproc_pool_= new int[KPAR_]; |
| 76 | + int quotient = GlobalV::NPROC/KPAR_; |
| 77 | + int residue = GlobalV::NPROC%KPAR_; |
| 78 | + // the previous "residue" pools have (quotient+1) processes |
| 79 | + for(int i=0;i<KPAR_;i++) |
| 80 | + { |
| 81 | + nproc_pool_[i] = quotient; |
| 82 | + if(i<residue) |
| 83 | + { |
| 84 | + ++nproc_pool_[i]; |
| 85 | + } |
| 86 | + } |
| 87 | + int color=-1; |
| 88 | + int np_now=0; |
| 89 | + for(int i=0;i<KPAR_;i++) |
| 90 | + { |
| 91 | + np_now += nproc_pool_[i]; |
| 92 | + if(GlobalV::MY_RANK < np_now) |
| 93 | + { |
| 94 | + color = i; |
| 95 | + // GlobalV::MY_POOL is the pool where this process resides |
| 96 | + EXPECT_EQ(GlobalV::MY_POOL,i); |
| 97 | + break; |
| 98 | + } |
| 99 | + } |
| 100 | + MPI_Comm test_comm; |
| 101 | + int test_rank, test_size; |
| 102 | + MPI_Comm_split(MPI_COMM_WORLD, color, GlobalV::MY_RANK, &test_comm); |
| 103 | + MPI_Comm_rank(test_comm, &test_rank); |
| 104 | + MPI_Comm_size(test_comm, &test_size); |
| 105 | + // GlobalV::RANK_IN_POOL is the rank of this process in GlobalV::MY_POOL |
| 106 | + EXPECT_EQ(GlobalV::RANK_IN_POOL,test_rank); |
| 107 | + // GlobalV::NPROC_IN_POOL is the number of processes in GlobalV::MY_POOL where this process resides |
| 108 | + EXPECT_EQ(GlobalV::NPROC_IN_POOL,test_size); |
| 109 | + //printf("my_rank: %d \t test rank/size: %d/%d \t pool rank/size: %d/%d\n", |
| 110 | + // GlobalV::MY_RANK,test_rank,test_size,GlobalV::RANK_IN_POOL,GlobalV::NPROC_IN_POOL); |
| 111 | + MPI_Comm_free(&test_comm); |
| 112 | +} |
| 113 | + |
| 114 | +class ParaKpoints : public ::testing::TestWithParam<ParaPrepare> |
| 115 | +{ |
| 116 | +}; |
| 117 | + |
| 118 | +TEST_P(ParaKpoints,DividePools) |
| 119 | +{ |
| 120 | + ParaPrepare pp = GetParam(); |
| 121 | + Parallel_Kpoints* Pkpoints; |
| 122 | + Pkpoints = new Parallel_Kpoints; |
| 123 | + GlobalV::KPAR = pp.KPAR_; |
| 124 | + if(pp.KPAR_>GlobalV::NPROC) |
| 125 | + { |
| 126 | + std::string output; |
| 127 | + testing::internal::CaptureStdout(); |
| 128 | + EXPECT_EXIT(Pkpoints->init_pools(),testing::ExitedWithCode(0),""); |
| 129 | + output = testing::internal::GetCapturedStdout(); |
| 130 | + EXPECT_THAT(output,testing::HasSubstr("Too many pools")); |
| 131 | + } |
| 132 | + else |
| 133 | + { |
| 134 | + Pkpoints->init_pools(); |
| 135 | + pp.test_init_pools(); |
| 136 | + Pkpoints->kinfo(pp.nkstot_); |
| 137 | + pp.test_kinfo(Pkpoints); |
| 138 | + } |
| 139 | + delete Pkpoints; |
| 140 | +} |
| 141 | + |
| 142 | +INSTANTIATE_TEST_SUITE_P(TESTPK,ParaKpoints,::testing::Values( |
| 143 | + // KPAR, nkstot |
| 144 | + ParaPrepare(2,57), |
| 145 | + ParaPrepare(3,67), |
| 146 | + ParaPrepare(5,97), |
| 147 | + ParaPrepare(97,97) |
| 148 | + )); |
| 149 | + |
| 150 | +int main(int argc, char **argv) |
| 151 | +{ |
| 152 | + |
| 153 | + MPI_Init(&argc, &argv); |
| 154 | + testing::InitGoogleTest(&argc, argv); |
| 155 | + |
| 156 | + MPI_Comm_size(MPI_COMM_WORLD,&GlobalV::NPROC); |
| 157 | + MPI_Comm_rank(MPI_COMM_WORLD,&GlobalV::MY_RANK); |
| 158 | + |
| 159 | + int result = RUN_ALL_TESTS(); |
| 160 | + |
| 161 | + MPI_Finalize(); |
| 162 | + |
| 163 | + return result; |
| 164 | +} |
| 165 | +#endif |
0 commit comments